【问题标题】:Implicit generic type conversion fails to match overloaded method signature隐式泛型类型转换无法匹配重载方法签名
【发布时间】:2016-08-31 21:04:30
【问题描述】:

我有一些类如下:

public class RowBase { }

public class SpecificRow : RowBase { }

public class RowListItem<TRow> where TRow : RowBase { }

public class SpecificRowListItem : RowListItem<SpecificRow> { }

还有一些方法如下:

public string GetName<TRow>(RowBase row) where TRow : RowBase { }

public string GetName<TRow>(RowListItem<TRow> item) where TRow : RowBase { }

我遇到的问题是RowListItem 的子类无法匹配第二个重载的签名。以下是示例:

var foo = new SpecificRow();
var bar = new SpecificRowListItem();
var baz = new RowListItem<SpecificRow>();
string name;
name = GetName(foo); // invokes first overload as expected
name = GetName(baz); // invokes second overload as expected
name = GetName(bar); // does not compile
name = GetName((RowListItem<SpecificRow>)bar); // this alternative invokes the second overload
name = GetName<SpecificRow>(bar); // this alternative also invokes the second overload

编译错误是

错误 CS0311 类型“ConsoleApplication1.SpecificRowListItem”不能用作泛型类型或方法“Program.GetName(TRow)”中的类型参数“TRow”。没有从“ConsoleApplication1.SpecificRowListItem”到“ConsoleApplication1.RowBase”的隐式引用转换。

由于SpecificRowListItemRowListItem&lt;TRow&gt; 的子类,其TRow 满足where TRow : RowBase 约束,我希望编译器能够告诉它在提供参数时它应该匹配第二个重载该类的一个实例。但是,编译器错误的文本表明它正在尝试匹配第一个重载 (GetName(TRow))。我想了解为什么会这样,以及除了两个可行的替代方案之外,我还能做些什么来解决这个问题。我试过这个:

public string GetName<TItem, TRow>(TItem item)
    where TItem : RowListItem<TRow>
    where TRow : RowBase

除了丑陋之外,它给了我同样的问题(似乎与第一个重载匹配)。

【问题讨论】:

    标签: c# generics implicit-conversion


    【解决方案1】:

    RowListItem&lt;SpecificRow&gt;RowListItem&lt;BaseRow&gt; 无关,它不是从它派生的。

    查看泛型中的协方差。这个答案可能会对您有所帮助:"out T" vs. "T" in Generics

    工作示例:

      using System;
    
    namespace CoVariance
    {
        public class RowBase { }
    
        public class SpecificRow : RowBase { }
    
        public class RowListItem<TRow> : IInputSave<TRow> where TRow : RowBase { }
    
        public class SpecificRowListItem : RowListItem<SpecificRow> { }
    
        internal interface IInputSave<out TRow>
            where TRow : RowBase
        {
        }
    
        class Program
        {
            public static void Main(string[] args){
    
                var foo = new SpecificRow();
                var bar = new SpecificRowListItem();
                var baz = new RowListItem<SpecificRow>();
                string name;
    
                name = GetName(foo);
                Console.WriteLine(name); //oink
                name = GetName(baz);
                Console.WriteLine(name); //nested oink
                name = GetName(bar);
                Console.WriteLine(name); //nested oink
                name = GetName((RowListItem<SpecificRow>)bar);
                Console.WriteLine(name); //nested oink
                //name = GetName<SpecificRow>(bar); 
    
                Console.ReadKey();
            }
    
            public static string GetName(RowBase row)
            {
                return "oink";
            }
    
            public static string GetName(IInputSave<RowBase> item)
            {
                return "nested oink";
            }
        }
    }
    

    【讨论】:

    • 谢谢,但我没有关注你。根据我对您的回答的理解,GetName((RowListItem&lt;SpecificRow&gt;)bar) 也应该失败,因为它不是源自RowListItem&lt;BaseRow&gt;。但是,它成功是因为where TRow : BaseRow 约束,它匹配任何从BaseRow 继承的TRow。我的问题是编译器是否有原因不能从SpecificRowListItem 隐式转换为RowListItem&lt;SpecificRow&gt;,即使第一个继承自第二个?
    • 我根据您在 c# 中利用协方差的示例在我的答案中添加了一个工作示例。但我无法正确地向你解释它,因为我自己并不完全理解它xD,但在互联网上有很多关于这些东西的内容:d
    • 我很高兴你也不理解它——让我觉得不那么傻了 ;-) This link 也很有趣。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-27
    相关资源
    最近更新 更多