Есть ли способ ограничить создание экземпляра вложенного класса в С#? Я хочу предотвратить создание вложенного класса из любого другого класса, кроме класса вложенности, но чтобы обеспечить полный доступ к вложенному классу из другого кода.
Видимость конструктора вложенных классов
Ответ 1
Обычно я создаю интерфейс для функций, которые вы хотите предоставить другим классам, а затем создайте вложенный класс private и реализуйте этот интерфейс. Таким образом, определение вложенного класса может оставаться скрытым:
public class Outer
{
private class Nested : IFace
{
public Nested(...)
{
}
//interface member implementations...
}
public IFace GetNested()
{
return new Nested();
}
}
Ответ 2
Короче говоря, нет, вы не можете этого сделать. Существует модификатор accessibity "public", который означает "доступный никем внутри меня или вне меня", и есть модификатор доступности "private", что означает "доступность чего-либо внутри меня". Не существует модификатора, который означает "доступный для вещи непосредственно вне меня, но не для чего-либо вне ее", и это то, что вам нужно будет пометить как конструктор. Это просто не концепция, о которой думали разработчики системы типов.
Можете ли вы описать, почему вам нужен этот сумасшедший вид доступности? Возможно, есть лучший способ получить то, что вы хотите.
Ответ 3
Если вам необходимо выполнить одно из следующих требований:
- Вы хотите, чтобы вложенный класс был запечатан,
- Вы не хотите копировать все вложенные подписи метода класса в интерфейс, например, в Ответ Ли,
Я нашел решение, подобное тому, которое было опубликовано 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()
, потому что
- Конструктор
-
Outer.Nested
приватен, поэтому он не может называть его напрямую -
Outer.Nested.Factory
может быть создан, но не может быть отброшен доIPrivateFactory
, поэтому его методCreateInstance()
не может быть вызван.
Обратите внимание, что я бы не рекомендовал использовать этот шаблон в основном в производственном коде, но это трюк, который мне очень пригодился в редких случаях.
Ответ 4
Поскольку в синтаксисе С# ничего нет, вам нужно будет реализовать что-то вроде "контракта" между ними. Вы можете воспользоваться тем, что вложенный класс может получить доступ к закрытым полям своего родителя:
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;
Ответ 5
Для ответа, предложенного Джошуа Смитом, мне было необходимо заставить статический конструктор FriendClass запускаться, достигнув путем вызова пустого статического метода Initalize() на FriendClass из статического конструктора 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 */);
}
Обратите внимание, что вы можете получить доступ к закрытым членам Outer from Nested.
Ответ 7
UPDATE: неправильный ответ, см. комментарии
Внутренний модификатор - это то, что вы ищете:
public class OuterClass
{
public class NestedClass {
internal NestedClass()
{
}
}
}
NestedClass будет виден всем, но конструктор будет доступен только для OuterClass.