Is there a way to limit the instantiation of the nested class in C#? I want to prevent nested class being instantiated from any other class except the nesting class, but to allow full access to the nested class from other code.
Usually I create an interface for the functionality you want to expose to other classes, then make the nested class private and implement that interface. This way the nested class definition can stay hidden:
public class Outer
{
private class Nested : IFace
{
public Nested(...)
{
}
//interface member implementations...
}
public IFace GetNested()
{
return new Nested();
}
}
If you need to meet one of the following requirements:
- You want the nested class to be sealed,
- You don't want to copy all the nested class's method signatures to an interface like in Lee's answer,
I found a solution similar to the one posted by ak99372, but without using a static initializer:
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();
}
}
The idea is that the Nested
class's constructor is accessible only to the Factory
class, which is nested one level deeper. The Factory
class explicitly implements the method CreateInstance
from the private interface IPrivateFactory
, so that only those who can see IPrivateFactory
can call CreateInstance
and get a new instance of Nested
.
Code outside the Outer
class can't freely create instances of Nested
without asking Outer.GetNested()
, because
Outer.Nested
's constructor is privated, so they can't call it directlyOuter.Nested.Factory
can be instantiated, but can't be cast toIPrivateFactory
, so itsCreateInstance()
method can't be called.
Note that I wouldn't recommend using that pattern heavily in production code, but it's a trick I find useful to have up my sleeve on rare occasions.
In short, no, you cannot do that. There is an accessibity modifier "public" which means "accessible by anything inside me or outside me" and there is an accessibility modifier "private" which means "accessible by anything inside me". There is no modifier which means "accessible to the thing immediately outside me but not to anything outside it", which is what you would need to mark the constructor as. That's simply not a concept that the designers of the type system thought would be useful.
Can you describe why you want this crazy kind of accessibility? Perhaps there is a better way to get what you want.
Since there is nothing in C# syntax you'll have to implement something like "a contract" between them. You can take advantage of the fact that nested class can access private fields of its parent:
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;
}
}
Of course you can adjust the contract to handle different parameters
private static Func<Arg1,Arg2,FriendClass> _friendContract;
With the new static abstract interface members of C# 11 you can limit the instantiation of nested classes quite neatly:
public class Outer
{
protected interface INestedFactory<T> where T : INestedFactory<T>
{
public static abstract T CreateInstance();
}
public class SomeNested : INestedFactory<SomeNested>
{
private SomeNested() { }
static SomeNested INestedFactory<SomeNested>.CreateInstance()
{
return new SomeNested();
}
}
protected void CreateNested<T>() where T : INestedFactory<T>
{
T.CreateInstance();
}
}
For the answer proposed by Joshua Smith I found it necessary to force the static constructor of FriendClass to run, achieved by calling an empty static Initalize() method on FriendClass from the static constructor of 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 */);
}
Note that you can access private members of Outer from Nested.
© 2022 - 2024 — McMap. All rights reserved.
implementing
. You don't re-invent design patterns.... – Earlearlainternal
is that it still leaves those members accessible to other types within the assembly. What C# needs is a "parent" visibility that only allows access from the type enclosing the nested type. – Ezra