【发布时间】:2013-05-02 13:26:22
【问题描述】:
目标
我的目标是实现一个密封的、公共的嵌套类,它只能由其封闭类创建 - 不使用反射。
这意味着嵌套类不能有任何公共或内部构造函数或任何公共或内部静态工厂方法。
以前的工作
This post from a couple of years ago seems to be the answer。 (整个线程有很多关于我想要实现的信息。)
它的工作原理非常简单:它利用嵌套类可以访问其封闭类的静态字段这一事实,以及嵌套类的静态构造函数。
封闭类声明了一个静态Func<NestedClassType, NestedClassCtorArgType>委托,它返回嵌套类的一个实例,以便封闭类可以将该委托用作工厂方法。
嵌套类本身有一个静态构造函数,它将封闭类的静态工厂委托初始化为将创建嵌套类实例的委托。
问题
不幸的是,我无法让它工作,因为它写在那个答案中。原因是嵌套类的静态构造函数没有在封闭类使用工厂方法之前被调用,因此存在空引用异常。 (如果您查看此问题末尾的示例程序,您会明白我的意思。)
我的解决方法
我已经解决了以下问题:
- 向嵌套类添加了一个不执行任何操作的内部静态
Initialise()方法。 - 向封闭类添加了一个静态构造函数,该构造函数调用嵌套类的
Initialise()方法。
这很好用,但会留下一点internal static void Initialise() 方法形状的痈。
我的问题
有没有办法避免这种方式?我不禁认为我在上面链接的原始帖子中遗漏了一些东西。我是不是误会了答案?
在我调用试图创建嵌套类实例的代码之前,是否有一种聪明的方法可以强制运行嵌套类的静态构造函数?
这种方法还有其他问题吗?
(我知道我可以为嵌套类编写一个公共接口,然后将其返回。这个问题不是要以这种方式解决它!)
示例代码
这是我的示例代码。尝试运行它,它会打印“Test”。然后尝试注释掉标记为<--- If you comment this out, things won't work 的行并再次运行。
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
Outer outer = new Outer();
Outer.Inner item = outer.Item("Test");
Console.WriteLine(item.Text);
}
}
public sealed class Outer
{
public Inner Item(string text)
{
return _nestedFactory(text);
}
// This static constructor calls the nested class's Initialise() method, which causes the
// nested class's static constructor to run, which then sets the enclosing class's
// _nestedFactory field appropriately.
static Outer()
{
Inner.Initialise(); // <--- If you comment this out, things won't work.
}
// This class has a private constructor.
// I only want class Outer to be able to create instances of it.
public sealed class Inner
{
private Inner(string value) // Secret private constructor!
{
text = value;
}
public string Text { get { return text; } }
static Inner()
{
_nestedFactory = text => new Inner(text);
}
internal static void Initialise(){}
readonly string text;
}
static Func<string, Inner> _nestedFactory;
}
}
【问题讨论】:
-
如果您愿意使用
internal Initialise()方法,为什么不愿意使用internal构造函数?这似乎是一个更简单的问题解决方案...... -
@MarcGravell 从调用者的角度来看,内部初始化方法不会做任何事情——它不会创建任何东西。而内部构造函数确实创造了一些东西;我认为这两件事完全不同。
-
@Matthew 那么让我问一下:为什么不愿意在这里使用
internal? -
@MarcGravell 实际上我很高兴将
internal用于Initialise方法,但我想知道是否有一种方法可以使更简单的方法起作用 - 如果您阅读我链接的原始答案,它得到了很多赞成,这使它看起来像它的作品,所以我想知道我是否误解了它。我意识到这在某种程度上是一种学术练习,但我经常从学术练习中学到很多东西。 :) -
我很好奇需要这种类设计的场景。你能详细说明一下吗?
标签: c# constructor nested-class method-hiding