Reputation: 2446
I've read a number of discussions on this topic on SO (and elsewhere), without being able to glean a clear answer.
I want to ensure that a given class A can only ever be created by a specific class B. In C++, I'd make the constructor of A private, and specify B as a friend. Now only B can ever create A.
What's the idiomatic way of doing this in C#, if indeed there is one at all?
Upvotes: 1
Views: 245
Reputation: 25810
You can't use the C++-style approach in C#.
I've encountered this before, and I usually solve it by making the class A abstract
(requires inheritance) and the constructor protected
(only classes inheriting from the class can call the constructor).
I then create a private
class within class B (called something like '_A') and inherit from A. (There's no additional code within _A.) _A defines a constructor which is public - thus visible to B (and B only, since _A is private).
Within B, you can create instances of _A and return them as A (via polymorphism).
I prefer this approach to the public interface because my class B code file ends up huge if class A is implemented within it. That's just my preference though - others may have different opinions.
abstract class A
{
protected A()
{
}
/* implementation details... */
}
public class B
{
public A GetInstance()
{
return new _A();
}
private class _A : A
{
public _A()
{
}
}
}
Upvotes: 3
Reputation: 2694
It's doable, but in a nasty way. Arguably more nasty then "friend" concept in C++.
You can declare private constructor and a static factory method where you would allow only specific type to call this method (by checking StackFrame).
public class Foo
{
private Foo() { }
public static Foo Create()
{
if(GetCallingType() != typeof(Bar))
{
throw new Exception("Only Bar can create Foo");
}
return new Foo();
}
private static Type GetCallingType()
{
return new StackFrame(2, false).GetMethod().DeclaringType;
}
}
Upvotes: 1
Reputation: 168988
I am assuming that external code needs to reference A
, but should not be able to create instances.
There is no simple way to achieve this. If you make A
's constructor internal
then only code within the same assembly as A
will be able to construct it (without using reflection).
You could create an instance of StackTrace
and check the frame at index 1 to see if it comes from a method of B
, but this may lead to performance issues, and is kind of a hack.
Upvotes: 1
Reputation: 498972
You can use a private inner class for this.
However, this is of limited use.
class B
{
private class A
{
}
}
Upvotes: 6