猿问

为什么 C# 编译器不认为这种泛型类型推断不明确?

鉴于以下类:


public static class EnumHelper

{

    //Overload 1

    public static List<string> GetStrings<TEnum>(TEnum value)

    {

        return EnumHelper<TEnum>.GetStrings(value);

    }


    //Overload 2

    public static List<string> GetStrings<TEnum>(IEnumerable<TEnum> value)

    {

        return EnumHelper<TEnum>.GetStrings(value);

    }

}

应用什么规则来选择其两种通用方法之一?例如,在以下代码中:


List<MyEnum> list;

EnumHelper.GetStrings(list);

它最终会调用EnumHelper.GetStrings<List<MyEnum>>(List<MyEnum>)(即 Overload 1),即使它看起来同样有效EnumHelper.GetStrings<MyEnum>(IEnumerable<MyEnum>)(即 Overload 2)。


例如,如果我完全删除重载 1,那么调用仍然可以正常编译,而不是选择标记为重载 2 的方法。这似乎使泛型类型推断有点危险,因为它正在调用一个直观上看起来更糟糕匹配的方法. 我正在传递一个 List/Enumerable 作为类型,它看起来非常具体,似乎应该匹配具有类似参数的方法(IEnumerable<TEnum>),但它选择了具有更通用的通用参数的方法(TEnum value)。


慕尼黑的夜晚无繁华
浏览 155回答 1
1回答

温温酱

应用什么规则来选择其两种通用方法之一?规范中的规则 - 不幸的是,这些规则非常复杂。在ECMA C# 5 标准中,相关位从第 12.6.4.3 节(“更好的函数成员”)开始。但是,在这种情况下,它相对简单。两种方法都适用,每种方法都分别进行类型推断:对于方法1,TEnum推断为List<MyEnum>对于方法2,TEnum推断为MyEnum接下来,编译器开始检查从参数到参数的转换,以查看一种转换是否比另一种“更好”。这进入第 12.6.4.4 节(“更好地从表达式转换”)。在这一点上,我们正在考虑这些转换:重载 1:&nbsp;List<MyEnum>to&nbsp;List<MyEnum>(TEnum推断为List<MyEnum>)重载 2:&nbsp;List<MyEnum>to&nbsp;IEnumerable<MyEnum>(TEnum推断为MyEnum)幸运的是,第一条规则可以帮助我们:给定从表达式 E 转换为类型 T1 的隐式转换 C1 和从表达式 E 转换为类型 T2 的隐式转换 C2,如果以下至少一项成立,则 C1 是比 C2 更好的转换:E 具有类型 S 并且存在从 S 到 T1 但不存在从 S 到 T2 的身份转换还有就是从身份转换List<MyEnum>到List<MyEnum>,但不是一个身份转换List<MyEnum>到IEnumerable<MyEnum>,因此第一次转换是更好的。没有任何其他转换需要考虑,因此重载 1 被视为更好的函数成员。如果此早期阶段以抢七局结束,您关于“更一般”与“更具体”参数的论点将是有效的,但事实并非如此:在“更具体的参数”之前考虑参数到参数的“更好的转换” .一般来说,两种重载解析都非常复杂。它必须考虑继承、泛型、无类型参数(例如空字面量、默认字面量、匿名函数)、参数数组、所有可能的转换。几乎每次向 C# 添加新功能时,它都会影响重载解析 :(
随时随地看视频慕课网APP
我要回答