背景:我已经使用嵌套类N封装了(父)E类,在E中有几个N实例。在封闭的(父)类中,我正在进行一些计算,我正在为嵌套类的每个实例设置值。像这样:
n1.field1 = ...;
n1.field2 = ...;
n1.field3 = ...;
n2.field1 = ...;
...
这是一个大的eval方法(在父类中)。我的意图是 - 因为所有计算都在父类中(它们不能按照嵌套实例进行,因为它会使代码更复杂) - 使setter仅对父类和getter公共可用。
现在有一个问题:
我被困 - 怎么做(限制访问父类,不多也不少)?
我怀疑我会先回答问题 - “但是为什么你不按每个字段拆分评估” - 所以我通过例子回答这个问题:你如何计算最小值和最大值一个集合?快点?答案是 - 一次通过。这就是为什么我有一个eval函数可以进行计算并一次设置所有字段。
答案 0 :(得分:48)
您可以在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; }
}
}
答案 1 :(得分:7)
如果您可以将父类和子类放在另一个程序集中,则可以使用internal
作为setter。这通常是如何在野外处理的。
<强> 修改 强>:
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
的方式,这可能会有效。
答案 2 :(得分:7)
另一种方法是,如果您的(嵌套)类是私有的,请将您希望成为私有的成员。如果私有类的字段是公共的,则它只会暴露给封闭类
public class E
{
public void Foo()
{
IN n = new N();
n.field1 = 42;
}
class N : IN
{
public int _field1;
}
}
现在N
仅对E
可见,因此n._field1
公开只对E
有意义,而且您是安全的..
答案 3 :(得分: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类实例的方法或特定字段的getter / setter 。
如果你不介意在你的内部类中有一个额外的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;
};
}
}
}
我知道无论如何都可以使用Reflection来绕过私有访问限制,但是在我看来,使用它只是为了调用一个单独的Init()方法然后分配适当的代理是一个更清洁,更通用的解决方案。另一种方法是为您可能想要创建的每个代表调用反射,即使这样,也可能存在限制(例如无法为构造函数创建委托)。
上面的解决方案不仅支持包装构造函数,而且它只会在程序的生命周期中使用Reflection一次,因此除了使用委托实现应该使用的事实之外,不应该有明显的性能损失。首先允许直接访问。我不知道为什么C#不支持这个,我想不出有什么理由不这样做。
答案 4 :(得分:-2)
将字段设为“受保护的内部”
如果嵌套类是私有的,则可以对这些字段使用obally“internal”。