.NET – 如何创建一个类,只有一个其他特定的类可以实例化它?

我想要进行以下设置:

class Descriptor { public string Name { get; private set; } public IList Parameters { get; private set; } // Set to ReadOnlyCollection private Descrtiptor() { } public Descriptor GetByName(string Name) { // Magic here, caching, loading, parsing, etc. } } class Parameter { public string Name { get; private set; } public string Valuie { get; private set; } } 

从XML文件加载后,整个结构将是只读的。 我想这样做,只有Descriptor类可以实例化一个参数。

一种方法是创建一个IParameter接口,然后在Descriptor类中使Parameter类私有,但在实际使用中,Parameter将有几个属性,我想避免重新定义它们两次。

这有点可能吗?

使其成为实现特定接口的私有嵌套类。 然后,只有外部类可以实例化它,但任何人都可以使用它(通过接口)。 例:

 interface IParameter { string Name { get; } string Value { get; } } class Descriptor { public string Name { get; private set; } public IList Parameters { get; private set; } private Descriptor() { } public Descriptor GetByName(string Name) { ... } class Parameter : IParameter { public string Name { get; private set; } public string Value { get; private set; } } } 

如果您确实必须避免使用该接口,则可以创建一个包含所有属性但声明受保护构造函数的公共抽象类。 然后,您可以创建一个私有嵌套类,该类inheritance自公共抽象,该公共抽象只能由外部类创建,并将其实例作为基类返回。 例:

 public abstract AbstractParameter { public string Name { get; protected set; } public string Value { get; protected set; } } class Descriptor { public string Name { get; private set; } public IList Parameters { get; private set; } private Descriptor() { } public Descriptor GetByName(string Name) { ... } private class NestedParameter : AbstractParameter { public NestedParameter() { /* whatever goes here */ } } } 

LBushkin有正确的想法。 如果要避免必须重新键入所有属性,只需右键单击该类的名称并选择“重构”>“提取接口”,它应该为您提供包含所有这些属性的接口。 (这适用于VS 2008,我不知道早期版本。)

C#通常采用的方法不是避免冗余代码,VS只会帮助您更快地编写代码。

您可以使用标记为Internal的构造函数。

这样它对程序集中的类是公开的,对它外面的类是私有的。

使用StrongNameIdentityPermission属性和SecurityAction.LinkDemand选项将类标记为与实例化(参数)“保护”:

 [StrongNameIdentityPermission(SecurityAction.LinkDemand, PublicKey="...")] class Parameter { ... } 

您需要提供适当的公钥。 因为您要求在Parameter类上检查链接时间(事实上是JIT时间),这意味着它只能在使用与使用与公钥匹配的私钥的强名称签名的程序集中使用。你在上面的属性构造函数中提供。 当然,您需要将Descriptor类放在一个单独的程序集中,并相应地赋予它一个强名称。

我在几个应用程序中使用了这种技术,它运行得非常好。

希望这可以帮助。

还有另一种方法:检查调用堆栈的调用类型。

如果只希望Descriptor类实例化一个Parameter,那么可以使Descriptor类成为Parameter的嵌套类。 (而不是相反)这是违反直觉的,因为容器或父类是嵌套类。

 public class Parameter { private Parameter() { } public string Name { get; private set; } public string Value { get; private set; } public static Parameter.Descriptor GetDescriptorByName(string Name) { return Parameter.Descriptor.GetByName(Name); } public class Descriptor { // Only class with access to private Parameter constructor private Descriptor() { // Initialize Parameters } public IList Parameters { get; private set; } // Set to ReadOnlyCollection public string Name { get; private set; } public static Descriptor GetByName(string Name) { // Magic here, caching, loading, parsing, etc. } } }