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

发布于 2024-08-15 18:28:35 字数 608 浏览 6 评论 0原文

我想要进行以下设置:

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 接口,然后在 Descriptor 类中将 Parameter 类设为私有,但在实际使用中,参数将具有多个属性,我想避免重新定义它们两次。

这有可能吗?

I'd like to have the following setup:

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

The whole structure will be read-only once loaded from an XML file. I'd like to make it so, that only the Descriptor class can instantiate a Parameter.

One way to do this would be to make an IParameter interface and then make Parameter class private in the Descriptor class, but in real-world usage the Parameter will have several properties, and I'd like to avoid redefining them twice.

Is this somehow possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

謸气贵蔟 2024-08-22 18:28:35

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

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 */ }
    }
}

Make it a private nested class that implements a particular interface. Then, only the outer class can instantiate it, but anyone can consume it (through the interface). Example:

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

If you really must avoid the interface, you can create a public abstract class that has all of the properties but declares a protected constructor. You can then create a private nested class that inherits from the public abstract that can only be created by the outer class and return instances of it as the base type. Example:

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 */ }
    }
}
欢烬 2024-08-22 18:28:35

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

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

LBushkin has the right idea. If you want to avoid having to retype all the properties just right-click the name of the class and choose "Refactor" > "Extract Interface", that should give you an interface that contains all those properties. (This works in VS 2008, I don't know about earlier versions.)

C# generally takes the approach that instead of avoiding redundant code, VS will just help you write it faster.

無心 2024-08-22 18:28:35

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

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

You could use a constructor marked Internal.

That way it's public to classes in the assembly, and private to classes outside of it.

过潦 2024-08-22 18:28:35

使用 StrongNameIdentityPermission 属性SecurityAction.LinkDemand 选项

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

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

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

希望这有帮助。

Mark the class to be "protected" from instantiation (Parameter) with the StrongNameIdentityPermission attribute and the SecurityAction.LinkDemand option:

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

You will need to provide the appropriate public key. Because you are demanding a link-time (JIT-time, in fact) check on the Parameterclass, this means that it can only be used from an assembly that is signed with a strong name that uses the private key matching the public key that you supply in the attribute constructor above. Of course, you will need to put the Descriptor class in a separate assembly and give it a strong name accordingly.

I have used this technique in a couple of applications and it worked very well.

Hope this helps.

迷路的信 2024-08-22 18:28:35

如果您只想使用 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. }
  }  
}

If you want only the Descriptor class to instantiate a Parameter, then you can make the Descriptor class a nested class of Parameter. (NOT the other way around) This is counterintuitive as the container or parent class is the nested class.

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. }
  }  
}
浮云落日 2024-08-22 18:28:35

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

There is another way: check the call stack for the calling type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文