方法重载允许我们定义许多具有相同名称但具有不同参数集的方法(因此具有相同的名称但签名不同)。
这两种方法是否已超载?
class A
{
public static void MyMethod<T>(T myVal) { }
public static void MyMethod(int myVal) { }
}
编辑:
语句A<int>.MyMethod(myInt);
不应抛出错误,因为构造类型A<int>
有两个具有相同名称和相同签名的方法吗?
答案 0 :(得分:46)
这两种方法是否已超载?
是
语句
A<int>.MyMethod(myInt);
不应该抛出错误,因为构造类型A<int>
有两个具有相同签名的方法吗?
这个问题没有意义; A
不是您声明的泛型类型。也许你打算问:
语句
A.MyMethod(myInt);
是否会导致编译器报告错误,因为有两种不明确的候选方法?
没有。正如其他人所说,在这种情况下,重载解析更喜欢非通用版本。有关详细信息,请参见下文。
或许你想问一下:
A类声明首先应该是非法的,因为在某种意义上它有两种具有相同签名的方法,
MyMethod
和MyMethod<int>
?
没有。 A型是完全合法的。 通用arity是签名的一部分。因此,没有两种方法具有相同的签名,因为第一种方法具有通用arity零,第二种方法具有通用arity one。
或许你想问一下:
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>
的程序。或者它可能崩溃。事实上它既没有;在糟糕的情况下,它能做到最好。
是否有这种类型构造的例子导致真正的实现定义行为?
是。有关详细信息,请参阅这些文章:
http://blogs.msdn.com/b/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx
http://blogs.msdn.com/b/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx
答案 1 :(得分:4)
是。当参数的类型为MyMethod(int myVal)
时,将调用int
,将为所有其他参数参数调用泛型重载,即使参数参数可隐式转换为(或者是派生类的)硬编码类型。重载决策将最适合,并且通用重载将在编译时解析为完全匹配。
注意:你可以 显式地调用泛型重载,并通过在方法调用中提供type参数来使用int
,正如Steven Sudit在他的回答中指出的那样。
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.
答案 2 :(得分:2)
是的,他们是。他们将允许代码:
A.MyMethod("a string"); // calls the generic version
A.MyMethod(42); // calls the int version
答案 3 :(得分:2)
是的,它们超载了。如果可用,编译器应该优先使用针对泛型方法的显式方法签名。但要注意,如果你可以避免这种过载,你可能应该这样做。有关于这种超载和意外行为的错误报告。
答案 4 :(得分:1)
是。它们具有相同的名称“MyMethod”但具有不同的签名。但是,C#规范专门处理这个问题,因为当两者都是选项时,编译器会更喜欢非泛型版本而不是泛型版本。
答案 5 :(得分:1)
是。如果你打电话给A.MyMethod(1);
,它总是运行第二种方法。您必须致电A.MyMethod<int>(1);
以强制它运行第一个。