c# - 为什么 C# 编译器不认为这种泛型类型推断有歧义?

标签 c# generics type-inference generic-type-argument

给定以下类:

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>) (即重载 1),尽管调用 EnumHelper.GetStrings<MyEnum>(IEnumerable<MyEnum>) 似乎同样有效(即重载 2)。

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

最佳答案

What rules are applied to select one of its two generic methods?

不幸的是,规范中的规则极其复杂。在ECMA C# 5 standard ,相关位从第 12.6.4.3 节(“更好的函数成员”)开始。

但是,在这种情况下,它相对简单。这两种方法都适用,每种方法分别进行类型推断:

  • 对于方法 1,TEnum推断为 List<MyEnum>
  • 对于方法 2,TEnum推断为 MyEnum

接下来,编译器开始检查参数到形参的转换,看一个转换是否比另一个“更好”。这进入第 12.6.4.4 节(“更好地从表达式转换”)。

此时我们正在考虑这些转化:

  • 重载 1:List<MyEnum>List<MyEnum> (因为 TEnum 被推断为 List<MyEnum> )
  • 重载 2:List<MyEnum>IEnumerable<MyEnum> (因为 TEnum 被推断为 MyEnum )

幸运的是,第一条规则在这里对我们有帮助:

Given an implicit conversion C1 that converts from an expression E to a type T1, and an implicit conversion C2 that converts from an expression E to a type T2, C1 is a better conversion than C2 if at least one of the following holds:

  • E has a type S and an identity conversion exists from S to T1 but not from S to T2

一个来自List<MyEnum>的身份转换至 List<MyEnum> , 但没有List<MyEnum> 进行的身份转换至 IEnumerable<MyEnum> , 因此第一次转换更好。

没有任何其他转换需要考虑,因此重载 1 被视为更好的函数成员。

如果这个早期阶段以平局结束,你关于“更通用”与“更具体”参数的争论将是有效的,但事实并非如此:参数到参数的“更好转换”在“更多”之前被考虑具体参数”。

一般来说,重载解析都非常复杂。它必须考虑继承、泛型、无类型参数(例如 null 文字、默认文字、匿名函数)、参数数组和所有可能的转换。几乎每次向 C# 添加新功能时,它都会影响重载解析:(

关于c# - 为什么 C# 编译器不认为这种泛型类型推断有歧义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50404989/

相关文章:

typescript - 联合类型和条件类型的问题

java - 访问者模式可以用于执行通用双重调度吗?

c# - 泛型方法中根据类型调用方法

algorithm - Damas-Hindley-Milner 类型推理算法实现

javascript - TypeScript:如何输入具有稍后添加的属性的对象?

c# - 什么是 System.Web.Extensions?

c# - 如何在没有 ef 的情况下在 MVC5 中使用参数进行搜索

c# - 绑定(bind)到 WPF 中的设计数据

c# - 关于多用户全局变量的思考

C# 泛型类型推断与协变 - 错误或限制