Visibility of nested class constructor

后端 未结 6 901
渐次进展
渐次进展 2021-02-13 18:41

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 allo

相关标签:
6条回答
  • 2021-02-13 19:10

    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.

    0 讨论(0)
  • 2021-02-13 19:12
    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.

    0 讨论(0)
  • 2021-02-13 19:13

    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.

    0 讨论(0)
  • 2021-02-13 19:15

    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();
        }
    }
    
    0 讨论(0)
  • 2021-02-13 19:24

    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;
    
    0 讨论(0)
  • 2021-02-13 19:28

    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.

    0 讨论(0)
提交回复
热议问题