嵌套类构造函数的可见性

发布于 2024-08-30 22:17:31 字数 65 浏览 5 评论 0原文

有没有办法限制C#中嵌套类的实例化?我想防止嵌套类从除嵌套类之外的任何其他类实例化,但允许从其他代码完全访问嵌套类。

Is there a way to limit the instantiation of the nested class in C#? I want to prevent nested class being instantiated from any other class except the nesting class, but to allow full access to the nested class from other code.

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

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

发布评论

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

评论(7

池予 2024-09-06 22:17:31

通常,我会为要向其他类公开的功能创建一个接口,然后将嵌套类设为私有并实现该接口。这样嵌套类定义可以保持隐藏:

public class Outer
{
    private class Nested : IFace
    {
        public Nested(...)
        {
        }
        //interface member implementations...
    }

    public IFace GetNested()
    {
        return new Nested();
    }
}

Usually I create an interface for the functionality you want to expose to other classes, then make the nested class private and implement that interface. This way the nested class definition can stay hidden:

public class Outer
{
    private class Nested : IFace
    {
        public Nested(...)
        {
        }
        //interface member implementations...
    }

    public IFace GetNested()
    {
        return new Nested();
    }
}
世界等同你 2024-09-06 22:17:31

如果您需要满足以下要求之一:

  • 您希望密封嵌套类,
  • 您不想将所有嵌套类的方法签名复制到 Lee的回答

我找到了类似于ak99372发布的解决方案 ,但不使用静态初始值设定项:

public class Outer
{
    private interface IPrivateFactory<T>
    {
        T CreateInstance();
    }

    public sealed class Nested
    {
        private Nested() {
            // private constructor, accessible only to the class Factory.
        }

        public class Factory : IPrivateFactory<Nested>
        {
            Nested IPrivateFactory<Nested>.CreateInstance() { return new Nested(); }
        }
    }

    public Nested GetNested() {
        // We couldn't write these lines outside of the `Outer` class.
        IPrivateFactory<Nested> factory = new Nested.Factory();
        return factory.CreateInstance();
    }
}

这个想法是 Nested 类的构造函数只能由 Factory 类访问,该类嵌套更深一层。 Factory 类显式实现私有接口 IPrivateFactory 中的 CreateInstance 方法,以便只有那些可以看到 IPrivateFactory 的人可以调用CreateInstance并获取Nested的新实例。

Outer 类外部的代码无法在不询问 Outer.GetNested() 的情况下自由创建 Nested 的实例,因为

  1. Outer.Nested< /code> 的构造函数是私有的,因此无法直接调用
  2. Outer.Nested.Factory 可以实例化,但无法强制转换为 IPrivateFactory,因此无法调用其 CreateInstance() 方法。

请注意,我不建议在生产代码中大量使用该模式,但我发现这是一个在极少数情况下有用的技巧。

If you need to meet one of the following requirements:

  • You want the nested class to be sealed,
  • You don't want to copy all the nested class's method signatures to an interface like in Lee's answer,

I found a solution similar to the one posted by ak99372, but without using a static initializer:

public class Outer
{
    private interface IPrivateFactory<T>
    {
        T CreateInstance();
    }

    public sealed class Nested
    {
        private Nested() {
            // private constructor, accessible only to the class Factory.
        }

        public class Factory : IPrivateFactory<Nested>
        {
            Nested IPrivateFactory<Nested>.CreateInstance() { return new Nested(); }
        }
    }

    public Nested GetNested() {
        // We couldn't write these lines outside of the `Outer` class.
        IPrivateFactory<Nested> factory = new Nested.Factory();
        return factory.CreateInstance();
    }
}

The idea is that the Nested class's constructor is accessible only to the Factory class, which is nested one level deeper. The Factory class explicitly implements the method CreateInstance from the private interface IPrivateFactory, so that only those who can see IPrivateFactory can call CreateInstance and get a new instance of Nested.

Code outside the Outer class can't freely create instances of Nested without asking Outer.GetNested(), because

  1. Outer.Nested's constructor is privated, so they can't call it directly
  2. Outer.Nested.Factory can be instantiated, but can't be cast to IPrivateFactory, so its CreateInstance() method can't be called.

Note that I wouldn't recommend using that pattern heavily in production code, but it's a trick I find useful to have up my sleeve on rare occasions.

春夜浅 2024-09-06 22:17:31

简而言之,不,你不能那样做。有一个可访问性修饰符“public”,意思是“可以被我内部或外部的任何东西访问”,还有一个可访问性修饰符“private”,意思是“可以被我内部的任何东西访问”。没有修饰符意味着“可以直接访问我之外的东西,但不能访问它之外的任何东西”,这就是您需要将构造函数标记为的修饰符。类型系统的设计者认为这根本不是一个有用的概念。

您能描述一下为什么您想要这种疯狂的可访问性吗?也许有更好的方法来获得你想要的东西。

In short, no, you cannot do that. There is an accessibity modifier "public" which means "accessible by anything inside me or outside me" and there is an accessibility modifier "private" which means "accessible by anything inside me". There is no modifier which means "accessible to the thing immediately outside me but not to anything outside it", which is what you would need to mark the constructor as. That's simply not a concept that the designers of the type system thought would be useful.

Can you describe why you want this crazy kind of accessibility? Perhaps there is a better way to get what you want.

孤星 2024-09-06 22:17:31

由于 C# 语法中没有任何内容,因此您必须在它们之间实现类似“合同”的内容。您可以利用嵌套类可以访问其父级的私有字段的事实:

public class ParentClass
{
  private static Func<FriendClass> _friendContract;

  public class FriendClass
  {
      static FriendClass()
      {
          _friendContract= () => new FriendClass();
      }

      private FriendClass() { }
  }

  ///Usage
  public FriendClass MethodUse()
  {
      var fInstance = _friendContract();
      //fInstance.DoSomething();
      return fInstance;
  }
}

当然您可以调整契约来处理不同的参数

 private static Func<Arg1,Arg2,FriendClass> _friendContract;

Since there is nothing in C# syntax you'll have to implement something like "a contract" between them. You can take advantage of the fact that nested class can access private fields of its parent:

public class ParentClass
{
  private static Func<FriendClass> _friendContract;

  public class FriendClass
  {
      static FriendClass()
      {
          _friendContract= () => new FriendClass();
      }

      private FriendClass() { }
  }

  ///Usage
  public FriendClass MethodUse()
  {
      var fInstance = _friendContract();
      //fInstance.DoSomething();
      return fInstance;
  }
}

Of course you can adjust the contract to handle different parameters

 private static Func<Arg1,Arg2,FriendClass> _friendContract;
郁金香雨 2024-09-06 22:17:31

使用 C# 11 的新静态抽象接口成员,您可以非常巧妙地限制嵌套类的实例化:

public class Outer
{
    protected interface INestedFactory<T> where T : INestedFactory<T>
    {
        public static abstract T CreateInstance();
    }

    public class SomeNested : INestedFactory<SomeNested>
    {
        private SomeNested() { }

        static SomeNested INestedFactory<SomeNested>.CreateInstance()
        {
            return new SomeNested();
        }
    }

    protected void CreateNested<T>() where T : INestedFactory<T>
    {
        T.CreateInstance();
    }
}

With the new static abstract interface members of C# 11 you can limit the instantiation of nested classes quite neatly:

public class Outer
{
    protected interface INestedFactory<T> where T : INestedFactory<T>
    {
        public static abstract T CreateInstance();
    }

    public class SomeNested : INestedFactory<SomeNested>
    {
        private SomeNested() { }

        static SomeNested INestedFactory<SomeNested>.CreateInstance()
        {
            return new SomeNested();
        }
    }

    protected void CreateNested<T>() where T : INestedFactory<T>
    {
        T.CreateInstance();
    }
}
明月夜 2024-09-06 22:17:31

对于 Joshua Smith 提出的答案,我发现有必要强制 FriendClass 的静态构造函数运行,这是通过从 ParentClass 的静态构造函数调用 FriendClass 上的空静态 Initalize() 方法来实现的。

For the answer proposed by Joshua Smith I found it necessary to force the static constructor of FriendClass to run, achieved by calling an empty static Initalize() method on FriendClass from the static constructor of ParentClass.

难如初 2024-09-06 22:17:31
public class Outer
{
    public class Nested
    {
        readonly Outer Outer;

        public Nested(Outer outer /* , parameters */)
        {
            Outer = outer;

            // implementation
        }

        // implementation
    }

    public Nested GetNested(/* parameters */) => new Nested(this /* , parameters */);
}

请注意,您可以从 Nested 访问 Outer 的私有成员。

public class Outer
{
    public class Nested
    {
        readonly Outer Outer;

        public Nested(Outer outer /* , parameters */)
        {
            Outer = outer;

            // implementation
        }

        // implementation
    }

    public Nested GetNested(/* parameters */) => new Nested(this /* , parameters */);
}

Note that you can access private members of Outer from Nested.

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