Видимость конструктора вложенных классов - PullRequest
11 голосов
/ 29 апреля 2010

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

Ответы [ 7 ]

27 голосов
/ 29 апреля 2010

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

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

    public IFace GetNested()
    {
        return new Nested();
    }
}
6 голосов
/ 29 апреля 2010

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

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

5 голосов
/ 02 февраля 2014

Если вам необходимо выполнить одно из следующих требований:

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

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

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

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

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

3 голосов
/ 24 января 2014

Поскольку в синтаксисе 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;
1 голос
/ 27 апреля 2016

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

0 голосов
/ 07 ноября 2017
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 из Nested.

0 голосов
/ 05 ноября 2013

ОБНОВЛЕНИЕ: неправильный ответ, см. Комментарии

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

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

        }
    }
}

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

...