通用方法解析

5

Consider the following code:

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类型参数添加到第二个重载方法中,从而使其成为泛型。请注意,类型参数未被使用。

这个修改导致了第一个DoSomething方法被调用。为什么?编译器有足够的信息来选择第二个方法。

您能否解释这种行为的原因,甚至更好的是,指向解释这种行为的C#规范的部分?

2个回答

10

在您的调用中,您没有指定类型参数 - 因此编译器必须推断T的类型。对于您的第二个方法,它无法做到这一点,因为声明的参数中从未提及类型参数。因此,该重载不适用并被忽略。

如果您在调用中指定了类型参数,例如:

DoSomething<int>(1)
DoSomething<object>(1)
DoSomething<string>(1)

如果在所有情况下都调用第二个重载。

根据C# 5规范第7.6.5.1节(方法调用),构建候选方法集时:

  • 如果F是泛型的,而M没有类型参数列表,则当:
    • 类型推断(§7.5.2)成功,推断出调用的类型参数列表,并且
    • 一旦将推断出的类型参数替换为相应的方法类型参数后,F中参数列表中的所有构造类型都满足其约束条件(§4.4.4),并且F的参数列表与A相关(§7.5.3.1)。

由于类型推断不成功,第二个方法不在候选集中,因此在进行真正的重载解析时,集合中只有一个方法(第一个方法)。


类型推断发生在编译时,在编译器尝试解析重载方法签名之前。 - Lloyd

-1

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接