Andre
Andre

Reputation: 3817

Generic Base class inheriting from Generic Interface

For some reason I am battling to implement a property from a generic interface by using a generic base class as follows:

public interface IParent<TChild> where TChild : IChild
{
    TChild Child { get; }
}

public interface IChild { }

Then I have a base class:

public class ParentBase<TChild> : IParent<TChild> where TChild : IChild
{
    private TChild _child;
    public ParentBase(TChild child)
    {
        this._child = child;
    }
    #region IParent<TChild> Members

    public TChild Child
    {
        get { return _child; }
    }

    #endregion
}

Now I have a new Parent Derivative and Child object as follows:

public class MyChild : IChild { }

public class MyParent : ParentBase<MyChild>, IParent<IChild> 
{
    public MyParent(MyChild child)
        : base(child)
    {
    }
}

I want to instantiate it and get the abstract (interface type) to pass to consumers as follows:

IParent<IChild> parent = new MyParent(new MyChild());

But for some reason I cannot implement the TChild correctly, even though I have defined the property public TChild Child on the ParentBase, the compiler says it is not implemented, even if i try implement explicitly. As you can see the constraints are all the way through to the base class.

Upvotes: 5

Views: 2723

Answers (3)

Phil
Phil

Reputation: 42991

You are deriving MyParent from ParentBase<MyChild> and IParent<IChild>. There is no implementation for

IParent<IChild> { IChild Child{get; } }

Adding an explicit implementation will allow your original code to compile

public class MyParent : ParentBase<MyChild>, IParent<IChild>
{
    public MyParent(MyChild child)
        : base(child)
    {
    }

    #region Implementation of IParent<IChild>

    IChild IParent<IChild>.Child
    { 
        get { return base.Child; }
    }

    #endregion
}

If you also make IParent covariant like this:

public interface IParent<out TChild> where TChild : IChild
{
    TChild Child { get; }
}

then you can now do this

IParent<IChild> parent = new MyParent(new MyChild());

or

ParentBase<MyChild> parent2 = new MyParent(new MyChild());

and

IParent<IChild> parent3 = parent2;

And as pointed out in the answer by @svick, with covariance you can then simplify by not deriving from IParent<IChild> and removing the explicit interface implementation.

Upvotes: 4

svick
svick

Reputation: 244757

This is exactly where generic variance is useful. If you marked your IParent interafce as covariant:

public interface IParent<out TChild> where TChild : IChild

and removed the explicit derivation of IParent<IChild> from MyParent:

public class MyParent : ParentBase<MyChild>

then MyParent can be treated as if it implemented IParent<IChild>. So for example, the following code would work:

MyParent parent = new MyParent(new MyChild());
IParent<IChild> iParent = parent;

Upvotes: 3

Tanzelax
Tanzelax

Reputation: 5714

If the consumers need to use get an IChild and not a TChild, can you not get rid of the generic interface?

public interface IParent
{
    public IChild Child { get; }
}

and then your inheritance works just fine

public class ParentBase<TChild> : IParent where TChild : IChild
{
    public IChild Child { get { return myChild; } }
}

and

public class MyParent : ParentBase<MyChild> // already implements IParent by the base doing so.
{
}

Upvotes: 0

Related Questions