方法重载允许我们定义多个具有相同名称但不同参数集(因此具有相同名称但不同签名)的方法。
这两个方法是否已经重载?
class A
{
public static void MyMethod<T>(T myVal) { }
public static void MyMethod(int myVal) { }
}
编辑:
语句 A<int>.MyMethod(myInt);
应该会抛出错误,因为构造类型 A<int>
有两个名称和签名相同的方法吗?
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 作为类型参数来构造这个东西!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/
int
时,MyMethod(int myVal)
将被调用,对于所有其他参数,泛型重载将被调用,即使参数可以隐式转换为(或是派生类)硬编码类型。重载解析将选择最佳匹配,并且泛型重载将在编译时解析为精确匹配。int
,通过在方法调用中提供类型参数。short s = 1;
int i = s;
MyMethod(s); // Generic
MyMethod(i); // int
MyMethod((int)s); // int
MyMethod(1); // int
MyMethod<int>(1); // Generic**
MyMethod(1.0); // Generic
// etc.
MyMethod(1)
,则IL显示对MyMethod(int32)
的调用,如果您使用MyMethod<int>(1)
,则为MyMethod<int32>
,如果您使用MyMethod(1.0)
,则为MyMethod<float64>
。我不是IL专家,但看起来解析的类型成为方法名称的一部分,消除了歧义。不过,我的理解可能完全错误。 - Anthony PegramReptile
和一个Lizard:Reptile
的情况下,当为Lizard lizard
调用Foo<T>(T t)
而不是Foo(Reptile reptile)
时。原因是?泛型将编译成与Lizard
的精确匹配,而不是使用与Reptile
足够接近的匹配。 - Anthony Pegram是的,它们可以。它们将允许像这样的代码:
A.MyMethod("a string"); // calls the generic version
A.MyMethod(42); // calls the int version
是的。它们都有相同的名称"MyMethod",但具有不同的签名。然而,C#规范明确指出,当两者均可选时,编译器将优先选择非泛型版本而非泛型版本。
是的。就我所知,如果您调用 A.MyMethod(1);
,它总会运行第二个方法。您需要调用 A.MyMethod<int>(1);
来强制运行第一个。