Tom Davies
Tom Davies

Reputation: 2446

Ensuring class A can only be created by class B

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

Answers (4)

JDB
JDB

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

pkmiec
pkmiec

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

cdhowie
cdhowie

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

Oded
Oded

Reputation: 498972

You can use a private inner class for this.

However, this is of limited use.

class B
{
  private class A
  {
  }
}

Upvotes: 6

Related Questions