【问题标题】:Type casting in method signatures in C#在 C# 中的方法签名中进行类型转换
【发布时间】:2015-09-17 17:21:39
【问题描述】:

我有 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
    {

    }
}

【问题讨论】:

标签: c# generics


【解决方案1】:

这是因为List&lt;T&gt;是C#中的Invariant类型,这意味着您只能使用最初在变量定义中指定的类型(即A)。您会注意到,如果将List&lt;A&gt; 替换为IEnumerable&lt;A&gt;,您的错误就会消失。这是因为IEnumerable&lt;A&gt;协变的,这意味着您可以使用比最初指定的更多派生类型(即B)。阅读有关Covariance and Contravariance in C# here 的更多信息。

【讨论】:

    【解决方案2】:

    如果您将List&lt;B&gt; 传递给fails,并且fails 尝试在其中添加A(因为List&lt;A&gt; 具有void Add(A item) 方法),您会怎么做期望发生?

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

    假设这段代码可以编译;当它尝试将A 添加到List&lt;B&gt; 时,它必须在运行时爆炸。这是一种类型安全的操作吗?

    如果您只想迭代List&lt;B&gt; 作为List&lt;A&gt;,您应该使用IEnumerable&lt;A&gt; 接口。 List&lt;B&gt; 可以被视为IEnumerable&lt;A&gt;,因为IEnumerable 接口是协变的。

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

    【讨论】:

    • 如果这不被认为是安全的,为什么编译器认为使用static void works&lt;T&gt;(List&lt;T&gt; aListType) where T : A 是安全的?这不会遇到同样的问题吗?
    • @Ringil 当您传入List&lt;B&gt; 时,该通用方法调用将解析为static void works(List&lt;B&gt; aListType)。为参数T 提供的类型参数是B。在预期 List&lt;B&gt; 的地方传递 List&lt;B&gt; 是类型安全的,这不足为奇。
    【解决方案3】:

    Marc Gravell 之前已经回答过这个问题。该解释非常适合您在此处了解您有哪些选择以及为什么您尝试的方法是不可能的。

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

    【讨论】:

      猜你喜欢
      • 2010-10-07
      • 2021-03-14
      • 2019-05-06
      • 1970-01-01
      • 2013-06-17
      • 2015-10-10
      • 1970-01-01
      • 2011-07-05
      • 2012-01-04
      相关资源
      最近更新 更多