2013-10-08 39 views
0

我很喜歡C++的友情功能。說,我們有一個家長和孩子。孩子的構造函數需要家長作爲參數:如何克服C#中缺乏友誼?

Child::Child(Parent & parent) 
{ 
    // Parent::RegisterChild is private 
    parent.RegisterChild(this); 
} 

由於友誼,父母與子女可以隨自己保持相當的安全控制 - 例如,當孩子改變家長,它可以通知前面的家長,它想成爲從其子項列表和新父項中分離出來,並將其附加到其列表中。這個解決方案的安全性意味着沒有任何來自Parent或Child的類可能會破壞這個機制。

不幸的是,C#不提供這樣的功能,如友誼。有一個internal訪問修飾符,但是它限制類元素大會的知名度,所以如果一個擴展組件,並引入新的類,該機制將不再是安全的。提取這些類來分離組件以提供安全性似乎是一個非常混亂的想法。

是否有使用現有的C#機制來提供兩個類,不能在派生類中被打破之間的這種密切和安全合作的方式?


編輯:針對評論

這不是信任的問題,因爲 - 正如埃裏克說 - 人,誰有權訪問的源代碼可以隨時打破它(刪除私人改性劑,添加另一個朋友類,不管)。這是一項安全措施,旨在防止人們犯下簡單,愚蠢的錯誤,後來很難跟蹤。我使用朋友來創建獨立的機制,嵌入基類中,這些機制在派生類中不能(或至少不能輕易地)被破壞。這樣,我和我的同事都不必擔心這些。

+0

我在C#中使用'private'訪問說明符並使用名爲'IFriendKey'的接口實現了類似於朋友的功能。 – Nawaz

+3

針對什麼攻擊不「安全」? 「內部」首先不是*安全*功能,因此提到「安全」是不起作用的。如果你的同事不能正確使用內部,那麼你認爲他們會正確使用「朋友」的原因是什麼?對於這一點,如果你不相信你的同事正確使用你的內部成員,那你爲什麼要給他們寫入源代碼的權限? –

+1

@EricLippert:通過「安全」,他可能意味着你通過使代碼的一部分「私人」,其他一些「受保護」等等達到同樣的目的。換句話說,如果你信任你的同事,那麼這是否意味着你不使用'private'? – Nawaz

回答

3

唯一的基於類型的訪問將被嵌套類型。如果將一種類型嵌套在另一種類型中,則嵌套類型可以訪問封閉類的所有成員,包括私有成員。嵌套類型也可以是私有的。例如:

public class Outer 
{ 
    // Code outside the body of Outer cannot call this. But 
    // the code in Nested *is* inside the body of Outer, so it's okay. 
    private void Foo() 
    { 
    } 

    private class Nested 
    { 
     internal void Bar() 
     { 
      new Outer().Foo(); 
     } 
    } 
} 

這可能是在某些情況下有益的,但顯然不是一個一般替代C++中的「朋友」類的概念。

有一點要注意的是InternalsVisibleToAttribute,其允許的另一個內部成員的一個組件的訪問。我知道在你的情況下,你實際上想要更多限制訪問比internal,但是[InternalsVisibleTo]仍然值得了解 - 它對測試特別有用。

0

這裏是什麼,我爲我的項目實施的基本思路和這個偉大工程。希望它也能爲你工作。請注意,這隻會在運行時強化友誼(這聽起來不太好)。

public interface IFriendKey { object Id {get; set;} } 

class Friend<TFriend> 
{ 
    protected void FriendAssert(IFriendKey key) 
    { 
     if (key == null || key.Id == null || key.Id.GetType() != typeof(TFriend)) 
      throw new Exception("No right to execute the called method."); 
    } 
} 

class A : Friend<B> 
{ 
    public void f(IFriendKey key) 
    { 
     FriendAssert(key); 
     Console.WriteLine("ONLY class B can execute this method successfully, even though it is declared public."); 
    } 
} 

class B 
{ 
    private class AFriendKey : IFriendKey 
    { 
     public object Id {get; set;} 
    } 

    IFriendKey Key { get { return new AFriendKey() {Id = this}; } } 

    public void g() 
    { 
     new A().f(this.Key); 
    } 
} 

public class Test 
{ 
    public static void Main() 
    { 
     new B().g(); 
    } 
} 

Online Demo

希望有所幫助。