Есть ли способ ограничить создание экземпляра вложенного класса в С#? Я хочу предотвратить создание экземпляра вложенного класса из любого другого класса, кроме класса вложенности, но разрешить полный доступ к вложенному классу из другого кода.
Видимость конструктора вложенного класса
Ответы (6)
Обычно я создаю интерфейс для функций, которые вы хотите предоставить другим классам, затем делаю вложенный класс закрытым и реализую этот интерфейс. Таким образом, определение вложенного класса может оставаться скрытым:
public class Outer
{
private class Nested : IFace
{
public Nested(...)
{
}
//interface member implementations...
}
public IFace GetNested()
{
return new Nested();
}
}
Короче говоря, нет, вы не можете этого сделать. Существует модификатор доступа «public», что означает «доступен для чего-либо внутри меня или вне меня», и есть модификатор доступности «private», который означает «доступен для чего-либо внутри меня». Нет модификатора, который означает «доступный к вещи, находящейся непосредственно вне меня, но не к чему-либо вне ее», что вам нужно пометить как конструктор. Это просто не та концепция, которую разработчики системы типов считали полезной.
Можете ли вы описать, почему вам нужна такая сумасшедшая доступность? Возможно, есть лучший способ получить то, что вы хотите.
Если вам необходимо выполнить одно из следующих требований:
- Вы хотите, чтобы вложенный класс был запечатан,
- Вы не хотите копировать все сигнатуры методов вложенного класса в интерфейс, как в ответе Ли,
Я нашел решение, похожее на сообщенное 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()
нельзя вызвать.
Обратите внимание, что я бы не рекомендовал активно использовать этот шаблон в производственном коде, но я считаю полезным использовать этот прием в редких случаях.
Поскольку в синтаксисе С# ничего нет, вам придется реализовать что-то вроде «контракта» между ними. Вы можете воспользоваться тем, что вложенный класс может получить доступ к закрытым полям своего родителя:
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 из Nested.
implementing
. Вы не изобретаете заново шаблоны проектирования.... - person James   schedule 29.04.2010internal
заключается в том, что он по-прежнему оставляет эти члены доступными для других типов в сборке. Что нужно C#, так это родительская видимость, которая разрешает доступ только из типа, включающего вложенный тип. - person Chris Charabaruk   schedule 09.02.2011