2010-05-12 91 views
12

背景:我用嵌套的類N封裝了(父類)E類,並在E中包含了幾個N的實例。在封閉的(父類)類中,我進行了一些計算,並且爲每個嵌套類實例設置了值。像這樣:如何訪問嵌套類的私有成員?

n1.field1 = ...; 
n1.field2 = ...; 
n1.field3 = ...; 
n2.field1 = ...; 
... 

這是一個大的eval方法(在父類中)。我的意圖是 - 因爲所有計算都在父類中(它們不能在每個嵌套實例中完成,因爲它會使代碼更加複雜) - 使setter只對父類和getters公開。

而且現在還有一個問題:

  • 當我提出制定者專用,父類不能存取權限他們
  • 當我讓他們公開,每個人都可以更改值
  • 和C#不有朋友的概念
  • 我不能在構造函數中傳遞值,因爲使用了惰性評估機制(所以在引用它們時必須創建實例 - 我創建所有對象並根據需要觸發計算)

我被困 - 如何做到這一點(限制訪問父級,不多,不少於)?


我懷疑我會首先得到的回答個問題 - 「但是你爲什麼不拆每個每個字段的評價」 - 所以我舉例回答這個問題:你是怎麼計算的最小值和最大值集合的價值?在一個快速的方式?答案是 - 一次過。這就是爲什麼我有一個eval函數來計算並一次設置所有字段。

+0

內部關鍵字不夠嗎? – Kimi 2010-05-12 08:13:12

+3

這太多了:-)。 – greenoldman 2010-05-12 11:25:26

+0

你不相信你的同事? – 2010-05-12 14:23:54

回答

7

如果可以將父類和子類放在另一個程序集中,則可以使用internal作爲設置程序。這通常是如何在野外處理的。

編輯

Thomas Levesque's answer給了我一個想法:

class Program 
{ 
    static void Main(string[] args) 
    { 
     E myE = new E(); 

     Console.WriteLine("E.N1.Field1 = " + myE.N1.Field1); 
     Console.WriteLine("E.N2.Field1 = " + myE.N2.Field1); 
    } 

    public interface IN 
    { 
     int Field1 { get; } 
    } 

    public class E 
    { 
     private N _n1 = new N(); 
     private N _n2 = new N(); 

     public E() 
     { 
      _n1.Field1 = 42; 
      _n2.Field1 = 23; 
     } 

     public IN N1 
     { 
      get { return _n1; } 
     } 

     public IN N2 
     { 
      get { return _n2; } 
     } 

     private class N : IN 
     { 
      private int _field1; 

      public int Field1 
      { 
       get { return _field1; } 
       set { _field1 = value; } 
      } 
     } 
    } 
} 

根據您需要公開的子類N,這可能是工作。

+1

謝謝,但它是一個單一的文件,不是那麼大,所以它似乎有點矯枉過正設置這個單獨的程序集。 – greenoldman 2010-05-12 08:45:58

+0

根據Thomas Levesque的回答更新了我的答案。 – Codesleuth 2010-05-12 09:29:15

+0

美(界面可以嵌套)。謝謝! – greenoldman 2010-05-12 10:51:28

-2

使字段「受保護的內部」

如果嵌套類是私有的,你可以使用obly「內部」到這些領域。

+0

田野不會暴露於整個裝配? – greenoldman 2010-05-12 08:35:32

+0

如果是「內部字段和私人類」:否,因爲該類是私人的。 另一種情況:是的。但是自己的裝配應該在你的控制之下。通常這不是問題。 – Jack 2010-05-12 09:06:22

+3

其實它總是一個問題 - 一年後,你可以擁有同樣的最佳意圖,但你可能會忘記設計。代碼應該反映設計,而不是評論或意願。 – greenoldman 2010-05-12 10:54:58

42

您可以在E內聲明專用接口IN,由N明確實施。此接口將只能通過E揭露N訪問的成員:

public class E 
{ 
    public void Foo() 
    { 
     IN n = new N(); 
     n.Field1 = 42; 
    } 

    public class N : IN 
    { 
     private int _field1; 

     int IN.Field1 
     { 
      get { return _field1; } 
      set { _field1 = value; } 
     } 
    } 

    private interface IN 
    { 
     int Field1 { get; set; } 
    } 
} 
+0

謝謝。接口不能被設置爲私有的,因爲我不會讀取父類之外的值(我需要公共getter),並且一旦公開,我也可以公開使用setter。 – greenoldman 2010-05-12 08:45:00

+2

我想你誤解了我的答案......「IN」接口永遠不會公開。這只是嵌套類僅向包含類公開屬性的一種方式。如果你需要,你也可以在'N'中創建公共getter。 – 2010-05-12 10:18:57

+0

如果接口是私有的,它不在父類之外。 – greenoldman 2010-05-12 10:45:57

4

另一種選擇是離開你希望成爲私有成員公共如果你的(嵌套)類是私有的。如果私人類的字段是公開的,它只會暴露給封閉的類。

public class E 
{ 
    public void Foo() 
    { 
     IN n = new N(); 
     n.field1 = 42; 
    } 

    class N : IN 
    { 
     public int _field1; 
    } 
} 

現在N僅僅是E可見的,所以n._field1公職僅事項E,你是安全的..

1

這是一個老問題,但在這裏不用那並不是一個可行的解決方案不要使用接口。

您可以在內部類設置代表在外部類中,像這樣一個靜態函數:

public class Outer { 
    private delegate void _operateDlg(Inner inner, bool value); 
    private static _operateDlg _validate; 

    static Outer() { 
     Inner.Init(); 
    } 

    public void Set(Inner inner, bool value) { 
     _validate(inner, value); 
    } 

    public class Inner { 
     public bool IsValid {get; private set; } 
     public static void Init() { 
      Outer._validate += delegate(Inner i, bool value) { 
       i.IsValid = value; 
      }; 
     } 
    } 
} 

你可以把各種不同的代表在你與分配外部類Inner.Init()方法,例如通過私有構造函數返回Inner類的實例或通過特定字段的getters/setters返回的方法。

如果你不介意在你的內部類中有一個額外的Init()靜態函數,那麼這並不需要改變。但是,如果你不想在init()方法是可見的,你可以使用反射來稱呼它:

using System.Reflection; 

public class Outer { 
    private delegate void _operateDlg(Inner inner, bool value); 
    private static _operateDlg _validate; 

    static Outer() { 
     typeof(Inner).GetMethod("Init", 
      BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, null); 
    } 

    public void Set(Inner inner, bool value) { 
     _validate(inner, value); 
    } 

    public class Inner { 
     public bool IsValid {get; private set; } 
     private static void Init() { 
      Outer._validate = delegate(Inner i, bool value) { 
       i.IsValid = value; 
      }; 
     } 
    } 
} 

我知道,一個可以使用反射反正繞過私人訪問限制,但只使用到在我看來,調用一個Init()方法然後分配合適的代表是一種更清潔和更靈活的解決方案。另一種方法是爲每個可能想要創建的委託調用反射,甚至可能會有限制(例如無法爲構造函數創建委託)。

上述解決方案不僅支持包裝構造函數,而且它只會在程序的生命週期中使用Reflection一次,所以除了使用代表實現什麼功能之外,不應該有明顯的性能損失應該首先被允許作爲直接訪問。我不知道爲什麼C#不支持這個,我想不出爲什麼它不支持。