真的不可能使用返回类型重载?

我用两种方法在MSIL中创建了一个小DLL:

float AddNumbers(int, int) int AddNumbers(int, int) 

正如你们中的一些人可能知道的那样,MSIL允许你创建具有相同参数的方法,只要你有不同类型的返回类型(所谓的返回类型重载)。 现在,当我试图从c#中使用它时,正如我所期待的那样,它引发了一个错误:

 float f = ILasm1.MainClass.AddNumbers(1, 2); 

错误是:

以下方法或属性之间的调用不明确:’ILasm1.MainClass.AddNumbers(int,int)’和’ILasm1.MainClass.AddNumbers(int,int)’

c#真的无法区分不同的返回类型吗? 我知道我不能编写只有不同返回类型的方法,但我总是假设它知道如何处理它。

像其他人一样,没有C#不支持这一点。 实际上,IL支持这一点的原因是因为你必须明确返回类型,就像参数一样。 例如,在IL你会说

 ldarg.0 ldarg.1 call int AddNumbers(int, int) 

IL实际上没有方法重载的概念: float AddNumbers(int, int)int AddNumbers(int, int)无关,就IL而言。 你必须提前告诉IL编译器所有内容,它永远不会试图推断你的意图(比如像C#这样的高级语言)。

请注意,大多数.NET语言和C#都会返回类型重载的一个例外:转换运算符。 所以

 public static explicit operator B(A a); public static explicit operator C(A a); 

编译成

 public static B op_Explicit(A a); public static C op_Explicit(A a); 

因为这是一个特殊的极端情况,必须支持原始类型(如int – > bool)和引用类型转换(否则你会得到一种非常迂腐的语言),这是处理,但不是作为一个案例方法重载。

ECMA-334 C#第8.7.3节

方法的签名包括方法的名称以及其forms参数的数量,修饰符和类型。 方法的签名不包括返回类型。

您可以使用通用方法:

 T AddNumbers(int a, int b) { if (typeof(T) == typeof(int) || typeof(T) == typeof(float)) { return (T)Convert.ChangeType(a + b, typeof(T)); } throw new NotSupportedException(); } 

是的,在C#中真的不可能,我知道C ++也不允许这样做,它与语句的解释方式有关:

 double x = AddNumbers(1, 2); 

这里的规则是赋值是右关联的,意味着右边的表达式首先被完全评估,然后才考虑赋值,在必要时应用隐式转换。

编译器无法确定哪个版本最合适。 使用一些任意规则只会招来很难找到错误。

它与这个简单的陈述有关:

 double y = 5 / 2; // y = 2.0 

问题是有一个从int到float的自动转换,所以它真的不知道你的意图。 你打算调用两个int的方法并返回一个int,然后将其转换为float,或者你打算调用两个int的方法并返回一个float? 最好有一个编译器错误,而不是做出错误的选择,并在你的应用程序中断之前不让你知道。

MSIL能够在同一个程序集中保存这两个方法与编译器确定调用哪个方法无关。

Covariant返回类型已经讨论了很多年,它们在Java中是部分允许的,C ++有一个特例,C#设计者在4.0中添加了一些小的改动 。

对于您的玩具问题,有一些简单的典型解决方案。 例如,您的float AddNumbers(int, int)可能总是与(float) AddNumbers(int, int) ,在这种情况下,不需要第二个函数。 通常情况下使用generics处理: AddNumbers( n1, n2) ,因此您最终会得到float AddNumbers(float, float)int AddNumbers(int, int)

现实场景更有可能是您想要返回的不同表示,但您不想重命名该方法。 在inheritance/覆盖用例中,您也可以使用generics来解决这个问题。

在少数情况下,我想要按照您的意愿去做,实际上更好的方法是更恰当地命名方法,因为从长远来看它更具可读性和可维护性。

这也在这里讨论过 。

位于http://blogs.msdn.com/abhinaba/archive/2005/10/07/478221.aspx的 MSIL / C#中的案例很特殊,因为它们是显式转换运算符。

不,没有办法做到这一点。 事实上,除了带有模板的C ++之外,没有语言支持它。 这显然太危险了。 再说一遍,如果你写的话

 var a = AddNumbers(1, 1); 

假设是什么类型a

或者如果你称之为

  double a = AddNumbers(1, 1); 

甚至

  AddNumbers(1, 1); 

它应该叫什么版本?

请记住,关于如何将一种类型隐式转换为另一种类型的规则非常复杂。 让我们来看看不编译的简单程序

 class Program { static int parse(int a) { return a; } static float parse(float a) { return a; } static void Main(string[] args) { double a = parse(1.0); } } 

如果您尝试编译它,编译器将给您一个错误

 error C2668: 'parse' : ambiguous call to overloaded function could be 'float parse(float)' 

因为1.0有double类型,编译器真的不知道在intfloat之间选择什么类型,所以它要求你给它一个提示。 所以你可以在调用函数之前继续转换参数。

但如果它是函数重载的返回类型,那你怎么做呢? 没有办法做到这一点。

如何使用指针传递返回类型作为参数?

 void AddNumbers(int a, int b, float *ret){ *ret = (float)(a + b); } void AddNumbers(int a, int b, int *ret){ *ret = (int)(a + b); } 

调用它会变成这样的:

 int a; float b; AddNumbers(1, 2, &a); AddNumbers(1, 2, &b);