Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
421 views
in Technique[技术] by (71.8m points)

c# - Passing a generic collection of objects to a method that requires a collection of the base type

Say I have a method that is expecting a generic collection parameter of a base type, see Test.MethodA(IEnumerable(BaseClass) listA) below. How come when I pass it a collection of a derived type the code wont build? Wouldn't all instances of DerivedClass also be a BaseClass?

I could have just created a new List(BaseClass) and passed that to MethodA(IEnumerable(BaseClass) listA). But I would think C# would be smart enough to know that a collection of DerivedClass has all the same properties as a collection of BaseClass.

Is using the List.Cast(T)() method as I've shown the best way to solve this problem?

abstract class BaseClass
{
    public int SomeField;
    public abstract string SomeAbstractField
    {
        get;
    }
}

class DerivedClass:BaseClass
{
    public override string SomeAbstractField
    {
        get { return "foo"; }
    }
}

class TestClass
{ 

    public void MethodA(IEnumerable<BaseClass> listA)
    {

    }

    public void MethodB()
    {
        List<DerivedClass> listB = new List<DerivedClass>();

        //Error 16  The best overloaded method match for 
        //TestClass.MethodA(List<BaseClass>)' 
        //has some invalid arguments
        this.MethodA(listB);

        //this works
        this.MethodA(listB.Cast<BaseClass>());
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Cast<>() is the best way to solve it at the moment. Your original version would work fine in C# 4.0 / .NET 4.0 though, where IEnumerable<T> is covariant in T.

(I've just verified it compiles under .NET 4.0 beta 1.)

Until .NET 4.0 and C# 4 come out, generics are invariant - IEnumerable<object> and IEnumerable<string> are effectively unrelated interfaces. Even in .NET 4.0, you wouldn't be able to do this with List<T> as the parameter type - only interfaces and delegates will be variant, and even then only when the type parameter is only used in appropriate positions (output positions for covariance, input positions for contravariance).

To learn more about variance in C# 4, read Eric Lippert's excellent series of blog posts about it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...