这两个方法重载了吗?
是的。
不应该声明A<int>.MyMethod(myInt); 抛出错误,因为构造类型A<int> 有两个具有相同签名的方法?
这个问题没有意义; A 不是您声明的泛型类型。也许你想问:
语句A.MyMethod(myInt);是否应该导致编译器报告错误,因为有两个模棱两可的候选方法?
没有。正如其他人所说,在这种情况下,重载决议更喜欢非泛型版本。详情见下文。
或者你的意思是问:
首先声明类型 A 是否应该是非法的,因为在某种意义上它有两个具有相同签名的方法,MyMethod 和 MyMethod<int>?
没有。 A 型是完全合法的。 泛型是签名的一部分。因此,没有两个方法具有相同的签名,因为第一个具有通用参数零,第二个具有通用参数一。
或者你的意思是问:
class G<T>
{
public static void M(T t) {}
public static void M(int t) {}
}
可以构造泛型类型G<T>,使其具有两个具有相同签名的方法。声明这样的类型合法吗?
是的,声明这样的类型是合法的。这通常是一个坏主意,但它是合法的。
然后你可能会反驳:
但我的 Addison-Wesley 发布的 C# 2.0 规范副本在第 479 页上声明“声明为相同名称的两个函数成员......必须具有参数类型,这样任何封闭构造类型都不能有两个具有相同姓名和签名的成员。“这是怎么回事?
最初设计 C# 2.0 时,这就是计划。然而,随后设计者意识到这种理想的模式将被视为非法:
class C<T>
{
public C(T t) { ... } // Create a C<T> from a given T
public C(Stream s) { ... } // Deserialize a C<T> from disk
}
现在我们说对不起哥们,因为你可以说C<Stream>,导致两个构造函数统一,整个类是非法的。那将是不幸的。显然,任何人都不太可能用 Stream 作为类型参数来构造这个东西!
不幸的是,该规范在文本更新为最终版本之前就已出版。第 479 页的规则不是我们实施的。
继续代表您提出更多问题:
如果你调用G<int>.M(123),或者在原始示例中调用A.MyMethod(123),会发生什么?
当由于泛型构造而面临具有相同签名的两种方法时,当重载决议面临时,泛型构造的方法被认为比“自然”的方法“不太具体”。不太具体的方法会输给更具体的方法。
那么,如果重载解析有效,为什么这是一个坏主意?
A.MyMethod 的情况还不错;通常很容易明确地确定使用哪种方法。但是G<int>.M(123) 的情况要糟糕得多。 CLR 规则使这种情况成为“实现定义的行为”,因此任何旧的事情都可能发生。从技术上讲,CLR 可以拒绝验证构造类型G<int> 的程序。或者它可能会崩溃。事实上,它两者都没有。它在糟糕的情况下尽其所能。
有没有这种类型构造导致真正实现定义的行为的例子?
是的。有关详细信息,请参阅这些文章:
https://ericlippert.com/2006/04/05/odious-ambiguous-overloads-part-one/
https://ericlippert.com/2006/04/06/odious-ambiguous-overloads-part-two/