Видимость конструктора вложенного класса

есть ли способ ограничить создание экземпляра вложенного класса В C#? Я хочу предотвратить экземпляр вложенного класса из любого другого класса, кроме класса вложенности, но разрешить полный доступ к вложенному классу из другого кода.

7 ответов


обычно я создаю интерфейс для функций, которые вы хотите предоставить другим классам, затем делаю вложенный класс частным и реализую этот интерфейс. Таким образом, определение вложенного класса может оставаться скрытым:

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

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

короче говоря, нет, вы не можете этого сделать. Существует модификатор доступности "public", который означает" доступный чем-либо внутри меня или вне меня", и есть модификатор доступности" private", который означает"доступный чем-либо внутри меня". Нет модификатора, который означает "доступный для вещи непосредственно вне меня, но не для чего-либо вне него", что вам нужно было бы отметить конструктором. Это просто не концепция, которую дизайнеры типа system думали бы полезный.

можете ли вы описать почему вы хотите этот сумасшедший вид доступности? Возможно, есть лучший способ получить то, что вы хотите.


Если вам нужно соотвествовать одно из следующих:

  • вы хотите, чтобы вложенный класс был запечатан,
  • вы не хотите копировать все сигнатуры метода вложенного класса в интерфейс, как в ли,

я нашел решение, как сообщение от 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 класс, который вложен на один уровень глубже. The Factory класс явно реализует метод CreateInstance из личного интерфейса IPrivateFactory, так что только те, кто может видеть IPrivateFactory можно назвать CreateInstance и получить новый экземпляр Nested.

код за пределами Outer класс не может свободно создавать экземпляры Nested без разрешения Outer.GetNested(), потому что

  1. Outer.Nestedконструктор Приватный, поэтому они не могут его вызвать прямо
  2. Outer.Nested.Factory может быть создан экземпляр, но не может быть приведен к IPrivateFactory, поэтому CreateInstance() метод не может быть вызван.

обратите внимание, что я бы не рекомендовал использовать этот шаблон в основном в производственном коде, но это трюк, который я считаю полезным иметь в рукаве в редких случаях.


поскольку в синтаксисе 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;

для ответа, предложенного Джошуа Смитом, я счел необходимым принудительно запустить статический конструктор FriendClass, достигнутый путем вызова пустого статического метода Initalize () на FriendClass из статического конструктора ParentClass.


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

обратите внимание,что вы можете получить доступ к частным членам Outer из вложенных.


UPDATE: неверный ответ, см. комментарии

внутренний модификатор - это то, что вы ищете:

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

        }
    }
}

NestedClass будет виден всем, но его конструктор будет доступен только для OuterClass.