Visibility of nested class constructor

♀尐吖头ヾ 提交于 2019-12-04 17:48:16

问题


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.


回答1:


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



回答2:


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.




回答3:


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.




回答4:


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;



回答5:


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.




回答6:


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.




回答7:


UPDATE: incorrect answer, see comments

The internal modifier is what you are looking for:

public class OuterClass
{
    public class NestedClass {
        internal NestedClass()
        {

        }
    }
}

NestedClass will be visible to all, but it's constructor will be available only to OuterClass.



来源:https://stackoverflow.com/questions/2736827/visibility-of-nested-class-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!