My aim is to write an abstract base class which contains a method for deriving “child instances”. In this method already some computation is done which is common in all deriving classes.
The difficulty is that the base class is not able to create the child class on its own. So I introduced a type parameter T
in my base class and a protected abstract
method which shall return an instance of T
.
public abstract class Base<T> where T : Base<T>
{
public T GetChild()
{
string param = ComplexComputation();
return NewInstanceFrom(param);
}
protected abstract T NewInstanceFrom(string param);
}
// --- somewhere else: ---
public class Derivative : Base<Derivative>
{
public Derivative() { }
protected sealed override Derivative NewInstanceFrom(string param)
{
return new Derivative(param);
}
private Derivative(string param)
{
// some configuration
}
}
The disadvantage of this approach is that I cannot ensure that NewInstanceFrom
is only invoked by the base class. It could also be invoked by classes inheriting from Derivative
. That’s what I want to avoid.
So I could encapsulate the functionality in a private class or delegate:
public abstract class Base<T> where T : Base<T>
{
public T GetChild()
{
string param = ComplexComputation();
return subElementDerivator(param);
}
protected Base<T>(Func<string, T> subElementDerivator)
{
this.subElementDerivator = subElementDerivator;
}
private Func<string, T> subElementDerivator;
}
// --- somewhere else: ---
public class Derivative : Base<Derivative>
{
public Derivative()
: base(deriveSubElement)
{
}
private Derivative(string param)
: base(deriveSubElement)
{
// some configuration
}
private static Derivative deriveSubElement(string param)
{
return new Derivative(param);
}
}
But this introduces a new object.
Is there a simpler way to prevent access to a functionality (which the base class shall have access to) from heirs of Derivative
?
You can use explicit interface implementation to hide your factory method. Any client can still call the Create
method after casting but at least intellisense won't help developers.
public interface ISecretFactory<T>
{
T Create(string param);
}
public abstract class Base<T> where T : Base<T>, ISecretFactory<T>
{
public T GetChild()
{
// We are sure type T always implements ISecretFactory<T>
var factory = this as ISecretFactory<T>;
return factory.Create("base param");
}
}
public class Derivative : Base<Derivative>, ISecretFactory<Derivative>
{
public Derivative()
{
}
private Derivative(string param)
{
}
Derivative ISecretFactory<Derivative>.Create(string param)
{
return new Derivative(param);
}
}
public class SecondDerivative : Derivative
{
public void F()
{
// intellisense won't show Create method here.
// But 'this as ISecretFactory<Derivative>' trick still works.
}
}
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