C# NET-如何使一个类只有一个其他特定的类可以实例化它?

C# NET-如何使一个类只有一个其他特定的类可以实例化它?,c#,.net,class,c#-3.0,access-modifiers,C#,.net,Class,C# 3.0,Access Modifiers,我想进行以下设置: class Descriptor { public string Name { get; private set; } public IList<Parameter> Parameters { get; private set; } // Set to ReadOnlyCollection private Descrtiptor() { } public Descriptor GetByName(string Name) { //

我想进行以下设置:

class Descriptor
{
    public string Name { get; private set; }
    public IList<Parameter> 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; }
}
类描述符
{
公共字符串名称{get;private set;}
公共IList参数{get;private set;}//设置为ReadOnlyCollection
私有描述符(){}
公共描述符GetByName(字符串名){//Magic here,缓存、加载、解析等}
}
类参数
{
公共字符串名称{get;private set;}
公共字符串值{get;private set;}
}
从XML文件加载后,整个结构将是只读的。我希望这样,只有描述符类可以实例化参数

一种方法是创建一个
ipParameter
接口,然后在描述符类中将
参数
类设置为私有,但在实际使用中,该参数将具有多个属性,我希望避免重新定义它们两次


这可能吗?

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


这样一来,它对程序集中的类是公共的,而对程序集中以外的类是私有的。

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

interface IParameter
{ 
    string Name { get; } 
    string Value { get; }
}

class Descriptor
{
    public string Name { get; private set; }
    public IList<IParameter> 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; }
    }
}
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<AbstractParameter> Parameters { get; private set; }

    private Descriptor() { }
    public Descriptor GetByName(string Name) { ... }

    private class NestedParameter : AbstractParameter
    {
        public NestedParameter() { /* whatever goes here */ }
    }
}
接口参数
{ 
字符串名称{get;}
字符串值{get;}
}
类描述符
{
公共字符串名称{get;private set;}
公共IList参数{get;private set;}
专用描述符(){}
公共描述符GetByName(字符串名){…}
类参数:IParameter
{
公共字符串名称{get;private set;}
公共字符串值{get;private set;}
}
}
如果确实必须避免接口,则可以创建一个具有所有属性但声明受保护构造函数的公共抽象类。然后,您可以创建一个私有嵌套类,该类继承自只能由外部类创建的公共抽象,并将其实例作为基类型返回。例如:

interface IParameter
{ 
    string Name { get; } 
    string Value { get; }
}

class Descriptor
{
    public string Name { get; private set; }
    public IList<IParameter> 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; }
    }
}
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<AbstractParameter> Parameters { get; private set; }

    private Descriptor() { }
    public Descriptor GetByName(string Name) { ... }

    private class NestedParameter : AbstractParameter
    {
        public NestedParameter() { /* whatever goes here */ }
    }
}
公共抽象抽象参数
{ 
公共字符串名称{get;protected set;}
公共字符串值{get;protected set;}
}
类描述符
{
公共字符串名称{get;private set;}
公共IList参数{get;private set;}
专用描述符(){}
公共描述符GetByName(字符串名){…}
私有类NestedParameter:AbstractParameter
{
public NestedParameter(){/*此处的内容*/}
}
}

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


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

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

如果您只希望描述符类实例化一个参数,则可以将描述符类设为嵌套的参数类。(并非相反)这是违反直觉的,因为容器或父类是嵌套类

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<Parameter> 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. }
  }  
}
公共类参数
{  
私有参数(){}
公共字符串名称{get;private set;}
公共字符串值{get;private set;}
公共静态参数.描述符GetDescriptorByName(字符串名称)
{
返回参数.Descriptor.GetByName(名称);
}
公共类描述符
{//只有类可以访问私有参数构造函数
私有描述符(){//初始化参数}
公共IList参数{get;private set;}//设置为ReadOnlyCollection
公共字符串名称{get;private set;}
公共静态描述符GetByName(字符串名){//Magic here,缓存、加载、解析等}
}  
}
用和标记要“保护”的类,使其不被实例化(参数):

您需要提供适当的公钥。因为您要求对
参数
类进行链接时间(实际上是JIT时间)检查,这意味着它只能从使用与您在上述属性构造函数中提供的公钥匹配的私钥的强名称签名的程序集中使用。当然,您需要将
描述符
类放在一个单独的程序集中,并相应地给它一个强名称

我在几个应用程序中使用了这种技术,效果非常好


希望这能有所帮助。

像这样的运行时检查通常是不可取的,因为它们都很昂贵(由于反射)和脆弱性-如果添加了新的派生类,该类也应该能够实例化该类型。由于其他原因,它们也是脆弱的:方法内联任何人?这仍然允许您创建参数的另一个子类并通过该子类实例化。也许将构造函数
设置为受保护的内部
。@Martinho:你错了。“受保护的内部”会阻止程序集外部的类子类化,这是一个常见的误解。您应该将其视为受保护的或内部的,而不是受保护的和内部的-即该类可以从程序集内部或外部的任何其他类派生,但只能在内部实例化。