如何访问嵌套类的私有成员?
Posted
技术标签:
【中文标题】如何访问嵌套类的私有成员?【英文标题】:how to get access to private members of nested class? 【发布时间】:2010-05-12 08:07:32 【问题描述】:背景:我已将(父)类 E 与嵌套类 N 与 E 中的 N 的几个实例封闭在一起。在封闭的(父)类中,我正在做一些计算,并为嵌套类的每个实例设置值。像这样的:
n1.field1 = ...;
n1.field2 = ...;
n1.field3 = ...;
n2.field1 = ...;
...
这是一个大的 eval 方法(在父类中)。我的意图是——因为所有计算都在父类中(它们不能在每个嵌套实例中完成,因为它会使代码更复杂)——使 setter 只对父类和 getter 可用。
现在有一个问题:
当我将设置器设为私有时,父类无法访问它们 当我将它们公开时,每个人都可以更改值 而C#没有朋友的概念 我无法在构造函数中传递值,因为使用了惰性求值机制(因此必须在引用它们时创建实例 -- 我创建所有对象并按需触发计算)我被卡住了——怎么做(限制访问父类,不多也不少)?
我怀疑我会先得到答案——“但为什么你不按每个字段拆分评估”——所以我举例回答这个问题:你如何计算最小值和最大值收藏?以快速的方式?答案是——一口气。这就是为什么我有一个 eval 函数,它可以一次进行计算并设置所有字段。
【问题讨论】:
内部关键字不够吗? “信任”应该在编码范围之外。代码要么坚如磐石,要么不是,你必须对它给予额外的信任。我更喜欢第一个:-) How to restrict access to nested class member to enclosing class? 的可能重复项 Eric Lippert 的评论令人惊讶和震惊,并说明了为什么 C# 的访问规则如此草率。访问与信任/安全无关......这完全是一个封装问题。嵌套类的成员应该总是可以被包含它们的类访问。他们不在 C# 中是糟糕的语言设计。具有讽刺意味的是,该语言强制内部类对外部类缺乏“信任”。 我也对 Eric Lippert 的评论感到震惊。我什至不相信自己,更不用说我的同事了!我使用可访问性级别来保证对象可能处于的状态。如果您依赖信任,为什么还要设置可访问性级别? 【参考方案1】:您可以在E
内部声明一个私有接口IN
,由N
显式实现。这个接口将暴露N
的成员只能由E
访问:
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;
【讨论】:
谢谢。接口不能设为私有,因为我不会读取父类之外的值(我需要公共 getter),一旦它是公共的,我也可以公开使用 setter。 我认为您误解了我的回答...IN
界面从未打算公开。这只是嵌套类仅向包含类公开属性的一种方式。如果需要,您还可以在 N
中创建公共 getter
如果接口是私有的,它在父类之外是不可用的。
嗯,对,就是这样……这样,只有父类可以设置嵌套类的私有字段
这个答案是天才。巨大的 +1!【参考方案2】:
如果您可以将父类和子类放在另一个程序集中,您可以使用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
,这可能会起作用。
【讨论】:
谢谢,但它是一个文件,不是那么大,所以设置这个单独的程序集似乎有点矫枉过正。 根据 Thomas Levesque 的回答更新了我的回答。 美(界面可嵌套)。谢谢! Thomas Levesque 的回答对我来说似乎有点奇怪。您将嵌套类设为私有,将接口设为公有(而 TL 的代码反之亦然)。这有什么意义?我认为重点是让外部类访问嵌套类的私有字段,同时将嵌套类暴露给外部世界。在您的情况下,外部类没有特殊权限,它可以像其他任何人一样通过接口访问 Field1。如果你想让嵌套类保持私有,接口可能根本不需要,你可以使用属性。【参考方案3】:另一种选择是将您希望成为私有的成员公开如果您的(嵌套)类是私有的。如果私有类的字段是公共的,它只会暴露给封闭类.
public class E
public void Foo()
IN n = new N();
n.field1 = 42;
class N : IN
public int _field1;
现在N
只对E
可见,所以n._field1
公开只对E
很重要,你很安全..
【讨论】:
【参考方案4】:这是一个老问题,但这里有一个不使用接口的可能解决方案。
您可以在内部类中有一个静态函数,它在外部类中设置委托,如下所示:
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() 方法分配的外部类中,例如通过私有构造函数或特定字段的 getter/setter 返回 Inner 类实例的方法.
如果你不介意在你的内部类中有一个额外的 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() 方法,然后分配适当的委托是一种更清洁、更通用的解决方案。另一种方法是为您可能想要创建的每个委托调用反射,即使这样也可能存在限制(例如无法为构造函数创建委托)。
上述解决方案不仅支持包装构造函数,而且在程序的生命周期中只使用一次反射,因此除了您使用委托来实现应该实现的目标之外,不应该有明显的性能损失首先被允许作为直接访问。我不知道为什么 C# 不支持这一点,我想不出它不支持的充分理由。
【讨论】:
【参考方案5】:使字段“受保护的内部”
如果嵌套类是私有的,您可以对这些字段使用“内部”。
【讨论】:
字段不会暴露给整个程序集吗? 在“内部字段和私有类”的情况下:否,因为该类是私有的。另一种情况:是的。但是自己的程序集应该在您的控制之下。通常这不是问题。 其实这一直是个问题——一年后,你可以有同样的最佳意图,但你可能会忘记设计。代码应该反映设计,而不是 cmets 或愿望。protected internal
表示受保护或内部...比内部更广泛的访问。在任何情况下,protected
在这里都无关紧要,因为嵌套类没有子类。以上是关于如何访问嵌套类的私有成员?的主要内容,如果未能解决你的问题,请参考以下文章