2010-04-29 6 views
11

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

+0

Похоже, вы изобретаете шаблон дизайна Синглтона. –

+0

@Bastiaan: вы имеете в виду 'внедрение'. Вы не заново изобретаете шаблоны дизайна .... – James

+0

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

ответ

27

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

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

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

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

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

+1

Сверху моей головы (потому что это моя забота об этом): Реализация IAsyncResult. –

+0

Неправильно, см. Мой ответ. – MatteoSp

+6

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

-1

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

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

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

     } 
    } 
} 

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

+2

Этот ответ неверен. Если у вас тогда есть 'class ThirdClass {void M() {var x = new OuterClass.NestedClass(); }} '. Помните, что оригинальный плакат хотел: «* Я хочу предотвратить создание вложенного класса из любого другого класса, кроме класса вложенности. *», И это явно не соответствует законопроекту. –

+0

Да ... ты прав. Я не заметил, что пытался вызвать конструктор из другой сборки, поэтому работал внутренний модификатор ... – MatteoSp

3

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

для меня статический конструктор внутреннего класса не вызван, и я получаю nullreferenceexception –

4

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

  • Вы хотите, чтобы вложенный класс, чтобы быть запечатаны,
  • Вы не хотите, чтобы скопировать все м вложенного класса, енят подписи в интерфейс, как в Lee's answer,

Я нашел решение, похожее на the one posted by 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 «s конструктор privated, поэтому они не могут назвать это непосредственно
  2. Outer.Nested.Factory может инстанциируемый , но не может быть отброшено до IPrivateFactory, поэтому его метод CreateInstance() не может быть вызван.

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

1

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

+0

Вы должны комментарий Джошуа, а не сообщение нового ответа, который на самом деле не один. –

0
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 from Nested.

Смежные вопросы