开发者

Why does a function that takes IEnumerable<interface> not accept IEnumerable<class>?

Say, for instance, I have a class:

public class MyFoo : IMyBar
{
    ...
}

Then, I would want to use the following code:

List<MyFoo> classList = new List<MyFoo>();
classList.Add(new MyFoo(1));
classList.Add(new MyFoo(2));
classList.Add(new MyFoo(3));

List<IMyBar> interfaceList = new List<IMyBar>(classList);

But this produces the error:

`Argument '1': cannot convert from 'IEnumerable<MyFoo>' to 'IEnumerable<IMyBar>' 

Why is this? Since MyFoo implements IMyBar, one would expect that an IEnumerable of MyFoo could be treated as an IEnumerable of IMyBar. A mundane real-world example being producing a list of cars, and then being told that it wasn't a list of vehicles.

It's only a minor annoyance, but if anyone can shed so开发者_StackOverflow社区me light on this, I would be much obliged.


This is going to work in C# 4.0! What you are talking about is called generic covariance.

In the meantime you can use the Cast extension method:

List<IMyBar> interfaceList = new List<IMyBar>(classList.Cast<IMyBar>());


This is supported in .NET 4.0 but not earlier.

http://msdn.microsoft.com/en-us/library/dd799517%28VS.100%29.aspx


To clarify, the reason it doesn't work now is because IEnumerable<MyClass> does not inherit from IEnumerable<MyBar>. I'll say that again: the enumerable of the derived type does not inherit from the enumerable of the base type. Rather, both types specialize the IEnumerable<T> generic type. In .Net 3.5 and lower, they have no other relationship beyond specialization (which is not inheritance) and are otherwise two completely different types in the type system.

.Net 4.0 will not change the way these types relate at all. They will still be two completely different types that relate only through specialization. What it will do is allow you to write methods that know about the specialization relationship and in some cases allow you substitute one when you wrote the other.


If you want to cast between IEnumerables (as you wrote in the headline of your question) and not between Lists (as you wrote in your question) you can wait for the c# 4.0 covariance feature. Before that day you can use extension methods. But I would not use the Cast extension method noted in other answers, but writing my own method, that can be only used for covariance casting in IEnumerable. When/If you switch to C# 4.0 you will easily find all places in your code where the cast will be redundant.

public static class cEnumerableExtensions
{
    public static IEnumerable<TResult> CovarianceConversion<TResult, TSource>(this IEnumerable<TSource> source)
        where TSource : TResult
    {
        foreach (var item in source)
        {
            yield return item;
        }
    }
}

Final Node. There seems to be no precompiler constant for the netframework 4.0, otherwise I would add

    #if DOTNET4
    [Obsolete("You can directly cast in C# 4.0.")]
    #endif
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜