Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Derived class instantiation in abstract base class in C#

Tags:

c#

inheritance

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?

like image 707
ominug Avatar asked Nov 01 '22 11:11

ominug


1 Answers

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.
    }
}
like image 108
Mehmet Ataş Avatar answered Nov 15 '22 04:11

Mehmet Ataş