隐式泛型类型转换无法匹配重载方法签名

Implicit generic type conversion fails to match overloaded method signature

我有一些class如下:

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 的子 class 无法匹配第二个重载的签名。以下是示例:

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

编译错误为

Error CS0311 The type 'ConsoleApplication1.SpecificRowListItem' cannot be used as type parameter 'TRow' in the generic type or method 'Program.GetName(TRow)'. There is no implicit reference conversion from 'ConsoleApplication1.SpecificRowListItem' to 'ConsoleApplication1.RowBase'.

因为 SpecificRowListItemRowListItem<TRow> 的子 class 并且 TRow 满足 where TRow : RowBase 约束,我希望编译器是当提供一个参数作为 class 的实例时,能够判断它应该匹配第二个重载。但是,编译器错误的文本表明它正在尝试匹配第一个重载 (GetName(TRow))。我想了解为什么会这样,如果除了两种有效的替代方案之外我还能做些什么来解决问题。我试过这个:

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

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

RowListItem<SpecificRow>RowListItem<BaseRow> 没有关系,它不是从它派生的。

检查泛型中的协方差。这个答案可能对你有帮助:"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";
        }
    }
}