10

我想要以下设置:

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; }
}

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

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

这有可能吗?

4

6 回答 6

21

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

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 */ }
    }
}
于 2009-12-18T16:06:27.513 回答
4

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

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

于 2009-12-18T16:13:50.590 回答
1

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

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

于 2009-12-18T16:06:24.503 回答
1

StrongNameIdentityPermission使用属性SecurityAction.LinkDemand选项将要“保护”的类从实例化(参数)中标记出来:

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

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

我已经在几个应用程序中使用了这种技术,并且效果很好。

希望这可以帮助。

于 2009-12-18T17:43:55.807 回答
0

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

于 2009-12-18T16:21:11.573 回答
-1

如果您只希望 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<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. }
  }  
}
于 2009-12-18T17:41:01.740 回答