在C#中的方法签名中键入cast

时间:2015-09-17 17:21:40

标签: c# generics

我有2个课程ABB继承自A。如果我有一个像这样的方法 void works(A aType)我可以传递一个B类型的对象。但是,void fails(List<A> aListType)类似List<B>类型的方法失败,因为Visual Studio抱怨它无法在List<A>List<B>之间进行转换。我可以用泛型来解决这个问题,但为什么它首先会失败?另外,我应该只使用泛型吗?

这是一个基本的例子:

using System.Collections.Generic;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            B bType1 = new B();
            works(bType1); // This works

            List<B> bListType1 = new List<B>();
            works(bListType1); // This works

            List<B> bListType2 = new List<B>();
            fails(bListType2); // This fails
        }

        static void works(A aType)
        {
            return;
        }

        static void works<T>(List<T> aListType) where T : A
        {
            return;
        }

        static void fails(List<A> aListType)
        {
            return;
        }

    }

    class A
    {

    }

    class B : A
    {

    }
}

3 个答案:

答案 0 :(得分:4)

因为List<T>是C#中的不变类型,这意味着您只能使用最初在变量定义中指定的类型(即{{1} })。您会注意到,如果将A替换为List<A>,则您的错误就会消失。这是因为IEnumerable<A>协变,这意味着您可以使用比最初指定的更多派生类型(即IEnumerable<A>)。详细了解Covariance and Contravariance in C# here

答案 1 :(得分:3)

如果您将List<B>传递给fails,并且fails某处的某个地方尝试向其添加A(因为List<A>已一个void Add(A item)方法),你期望发生什么?

static void Fails(List<A> items)
{
    aListType.Add(new A());
}

...

Fails(new List<B>());

让我们说这段代码编译;当它试图将A添加到List<B>时,它必须在运行时爆炸。这是一种类型安全的操作吗?

如果您只想List<B>作为List<A> 迭代,则应使用IEnumerable<A>界面。 List<B> 可以被视为IEnumerable<A>,因为IEnumerable界面是协变的。

static void AlsoWorks(IEnumerable<A> items)
{
    foreach(var a in items)
    {
        Console.WriteLine("No problems here!");
    }
}

...

AlsoWorks(new List<B>());

答案 2 :(得分:0)

Marc Gravell之前已经回答了这个问题。这里的解释非常适合您理解您所拥有的选项以及您尝试的原因。

https://stackoverflow.com/a/5832173/1347784