Trident D'Gao
Trident D'Gao

Reputation: 19690

Covariance/contravariance: how to make the following code compile

UPDATE: The following code only makes sense in C#4.0 (Visual Studio 2010)

It seems like I am having some misunderstanding of covariance/contravariance thing. Can anybody tell me why the following code doesn't compile?

public class TestOne<TBase>
{
    public IEnumerable<TBase> Method<TDerived>(IEnumerable<TDerived> values)
        where TDerived: TBase
    {
        return values;
    }
}

while this one compiles: (!!!)

public interface IBase
{
}
public interface IDerived: IBase
{
}
public class TestTwo
{
    public IEnumerable<IBase> Method(IEnumerable<IDerived> values)
    {
        return values;
    }
}

Upvotes: 13

Views: 246

Answers (3)

linepogl
linepogl

Reputation: 9335

I cannot think of any situation where you actually need TDerived. Using TBase is sufficient:

public class TestOne<TBase>
{
    public IEnumerable<TBase> Method(IEnumerable<TBase> values)
    {
        return values;
    }
}

After all, you have no information about TDerived apart from the fact that it is a TBase...

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500435

Covariance only applies to reference types (for the type arguments), so you have to add a class constraint:

public IEnumerable<TBase> Method<TDerived>(IEnumerable<TDerived> values)
    where TDerived : class, TBase
{
    return values;
}

This will prevent you from trying to convert, say, an IEnumerable<int> into an IEnumerable<object>, which is invalid.

Upvotes: 13

devstruck
devstruck

Reputation: 1507

Neither compiled for me initially. Both failed on the implicit cast from Super(T/I) to Base(T/I). When I added an explicit case, however, both compiled.

public IEnumerable<TBase> Method<TSuper>(IEnumerable<TSuper> values)
    where TSuper: TBase
    {
        return (IEnumerable<TBase>) values;
    }

Upvotes: 0

Related Questions