泛型方法解析

本文关键字:泛型方法 | 更新日期: 2023-09-27 18:18:26

考虑以下代码:

public class Tests
{
    public void Test()
    {
        Assert.AreEqual("Int", DoSomething(1));
    }
    public static string DoSomething<T>(T value)
    {
        return "Generic";
    }
    public static string DoSomething(int value)
    {
        return "Int";
    }
}
如预期的那样,非泛型DoSomething方法将被调用。现在考虑以下修改:
public class Tests
{
    public void Test()
    {
        Assert.AreEqual("Int", DoSomething(1));
    }
    public static string DoSomething<T>(T value)
    {
        return "Generic";
    }
    public static string DoSomething<T>(int value)
    {
        return "Int";
    }
}

我唯一改变的是将T类型参数添加到第二个重载中,从而使其成为泛型。注意,这里没有使用type参数。

这个修改导致第一个DoSomething方法被调用。为什么?编译器拥有选择第二种方法所需的所有信息。

你能解释一下为什么,或者更好的是,指出c#规范中解释这种行为的部分吗?

泛型方法解析

在调用中,您没有指定类型参数-因此编译器将不得不推断T的类型。对于第二个方法则不能这样做,因为类型参数从未在声明的参数中提到过。因此,该重载不适用,将被忽略。

如果您为调用指定了类型参数,例如

中的任何一个
DoSomething<int>(1)
DoSomething<object>(1)
DoSomething<string>(1)

…然后在所有情况下都将调用第二个重载。

从c# 5规范的7.6.5.1节中,(方法调用)在构造候选方法集时:

  • 如果F是泛型且M没有类型参数列表,则F在以下情况下是候选的:
    • 类型推断(§7.5.2)成功,推断了调用的类型参数列表,并且
    • 一旦推断的类型参数被替换为相应的方法类型参数,F的参数列表中的所有构造类型都满足其约束(§4.4.4),并且F的参数列表适用于A(§7.5.3.1)。

由于类型推断没有成功,第二个方法不在候选集合中,所以当我们得到真正的重载解析时,该集合只有一个方法在(第一个)中。

编译器不能确定DoSomething(1)调用中的模式类型,但如果指定[int],它将选择另一个方法