Is it possible to create an abstract method that must return an instance of the derived class? I can do this:
abstract class Base
{
public abstract Base GetObj();
}
class Derived : Base
{
public Derived() { }
public override Base GetObj()
{
return new Derived();
}
}
But I was wondering if there was a way to do it such that Derived::GetObj()
is forced to return a Derived
?
Thanks.
Using generics should make this possible:
abstract class Base<T>
where T : Base<T>
{
public abstract T GetObj();
}
class Derived : Base <Derived>
{
public Derived() { }
public override Derived GetObj()
{
return new Derived();
}
}
You could even simplify this even more (if all of the derived instances are created with default constructors):
abstract class Base<T>
where T : Base<T>, new()
{
public static T GetObj()
{
return new T();
}
}
class Derived : Base<Derived>
{
public Derived() { }
}
What you have is almost but not quite exactly an abstract factory. I will first say that you should leave it up to the implementers of the derived classes to get it right, or simply trust that they will.
Another answer has shown what is known as the curiously recurring template pattern. It is where you have a base class that tries to use the type system to enforce that derived types use itself at certain input or output positions.
public abstract class Foo<T> where T : Foo<T>
public class Bar : Foo<Bar>
This idea might work in other languages. It works in C# only so far as people use it correctly. With the above definition of Bar, now I can also have
public class Baz : Foo<Bar>
Which is perfectly legal. Bar
is a Foo<Bar>
, which is all that is required for Baz to use it. Nothing requires Baz to actually use Foo<Baz>
.
The type system in C# simply cannot enforce what you would like enforced. Even with this pattern in place, you are still in the same position as before. You still have to trust the implementers of the derived classes to do it correctly.
For more on this topic, you might read this blog.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With