通用方法和方法重载

时间:2010-09-09 18:40:57

标签: c# generics

方法重载允许我们定义许多具有相同名称但具有不同参数集的方法(因此具有相同的名称但签名不同)。

这两种方法是否已超载?

class A
{
    public static void MyMethod<T>(T myVal) { }
    public static void MyMethod(int myVal) { }
}

编辑:

语句A<int>.MyMethod(myInt);不应抛出错误,因为构造类型A<int>有两个具有相同名称和相同签名的方法吗?

6 个答案:

答案 0 :(得分:46)

  

这两种方法是否已超载?

  

语句A<int>.MyMethod(myInt);不应该抛出错误,因为构造类型A<int>有两个具有相同签名的方法吗?

这个问题没有意义; A不是您声明的泛型类型。也许你打算问:

  

语句A.MyMethod(myInt);是否会导致编译器报告错误,因为有两种不明确的候选方法?

没有。正如其他人所说,在这种情况下,重载解析更喜欢非通用版本。有关详细信息,请参见下文。

或许你想问一下:

  

A类声明首先应该是非法的,因为在某种意义上它有两种具有相同签名的方法,MyMethodMyMethod<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)

是的,它们超载了。如果可用,编译器应该优先使用针对泛型方法的显式方法签名。但要注意,如果你可以避免这种过载,你可能应该这样做。有关于这种超载和意外行为的错误报告。

https://connect.microsoft.com/VisualStudio/feedback/details/522202/c-3-0-generic-overload-call-resolution-from-within-generic-function

答案 4 :(得分:1)

是。它们具有相同的名称“MyMethod”但具有不同的签名。但是,C#规范专门处理这个问题,因为当两者都是选项时,编译器会更喜欢非泛型版本而不是泛型版本。

答案 5 :(得分:1)

是。如果你打电话给A.MyMethod(1);,它总是运行第二种方法。您必须致电A.MyMethod<int>(1);以强制它运行第一个。