I have a class Foo
and a static class FooFactory
, which is used to create instances of Foo
and Foo
derived classes via the following API:
public static class FooFactory {
public static T Create<T>() where T : Foo, new() {
...
return new T();
}
}
The new()
specialization of the T
type parameter requires Foo
to have a public
default constructor. In other words, nothing is preventing a user of Foo
to initialize the class directly via the constructor.
However,
FooFactory
is intended to keep track of allFoo
instances, so I want to enforce the user to create allFoo
andFoo
derived instances via theFooFactory
.
The closest I have been able to prevent direct constructor initialization is to decorate the Foo
default constructor with the [Obsolete("message", error: true)]
attribute:
public class Foo {
[Obsolete("Fail", true)]
public Foo() { ... }
}
With this decoration the code does not compile when I call the Foo
default constructor directly, whereas initialization via FooFactory.Create<Foo>()
works.
But with this [Obsolete]
decoration, I still have problems with derived classes. The following won't even compile due to the error: true
setting for the Foo
default constructor:
public class Bar : Foo { ... }
public class Baz : Foo { public Baz() : base() { ... } }
I can declare a protected
Foo
constructor overload that the derived classes invoke instead of the default constructor, but then I will have no ability to programmatically prevent direct initialization of the derived classes.
If I set error
in the ObsoleteAttribute
to false
, I get compilation warnings instead, but I would like to have stronger discouragement than warnings...
Is there any way that I can programmatically prevent direct invocation of the default constructor for both Foo
and derived classes when the default constructors are required to be declared public
?
You cannot inherit from class with private constructor only but you can make your empty constructor private and add constructor with property like createdInsideFooFactory. You should also remove new() constraint in your factory. This is a hack but will let developer know that instance should be created inside foo factory.