37

假设我有两个 C# 方法的重载版本:

void Method( TypeA a ) { }
void Method( TypeB b ) { }

我用以下方法调用该方法:

Method( null );

调用方法的哪个重载?我可以做些什么来确保调用特定的重载?

4

6 回答 6

73

这取决于TypeATypeB

  • 如果其中有一个是适用的(例如,没有从nullto的转换,TypeB因为它是一个值类型,但是TypeA是一个引用类型),那么将对适用的那个进行调用。
  • 否则取决于 和 之间的TypeA关系TypeB
    • 如果存在从 to 的隐式转换TypeATypeB没有从TypeBto的隐式转换,TypeA则将使用重载 using TypeA
    • 如果存在从 to 的隐式转换TypeBTypeA没有从TypeAto的隐式转换,TypeB则将使用重载 using TypeB
    • 否则,调用是模棱两可的,将无法编译。

有关详细规则,请参阅 C# 3.0 规范的第 7.4.3.4 节。

这是一个不模棱两可的例子。这里TypeB派生自,这意味着存在从toTypeA的隐式转换,但反之则不然。因此使用了重载 using :TypeBTypeATypeB

using System;

class TypeA {}
class TypeB : TypeA {}

class Program
{
    static void Foo(TypeA x)
    {
        Console.WriteLine("Foo(TypeA)");
    }

    static void Foo(TypeB x)
    {
        Console.WriteLine("Foo(TypeB)");
    }

    static void Main()
    {
        Foo(null); // Prints Foo(TypeB)
    }
}

通常,即使面对其他模棱两可的调用,为了确保使用特定的重载,只需强制转换:

Foo((TypeA) null);

或者

Foo((TypeB) null);

请注意,如果这涉及声明类中的继承(即一个类正在重载由其基类声明的方法),那么您将陷入另一个问题,您需要转换方法的目标而不是参数。

于 2009-04-05T19:51:09.527 回答
8

Jon Skeet 给出了一个全面的答案,但从设计的角度来看,你不应该依赖于编译器规范的极端情况。如果不出意外,如果您必须在编写之前查看它的作用,那么下一个尝试阅读它的人也不会知道它的作用。它是不可维护的。

重载是为了方便起见,两个具有相同名称的不同重载应该做同样的事情。如果这两种方法做不同的事情,重命名它们中的一个或两个。

重载方法更常见的是具有不同数量的参数的变体,而具有较少参数的重载则提供合理的默认值。

egstring ToString(string format, System.IFormatProvider provider)具有最多的参数,
string ToString(System.IFormatProvider provider)提供默认格式,并
string ToString()提供默认格式和提供程序,

于 2009-04-05T20:26:21.377 回答
5

Jon Skeet 已经回答了默认选择哪个重载,但是如果你想确保调用特定的重载,使用命名参数通常比强制转换更好。

如果你有:

void Method( TypeA a ) { }
void Method( TypeB b ) { }

您可以致电Method(a: null);Method(b: null);

于 2015-04-22T12:29:15.100 回答
1

模棱两可的电话。(编译时错误)。

于 2009-04-05T19:50:15.283 回答
0

一个简单的解决方案是创建另一个具有以下签名的方法:

void Method() { }

或者更好地将其中一种方法的签名更新为:

void Method( TypeB b = null ) { }

然后这样称呼它:

Method();

在编译时,该值null是无类型的,因此编译器无法将其与方法签名之一匹配。在运行时,任何可能解析为的变量null仍将被键入,因此不会导致问题。

于 2014-03-22T13:09:28.543 回答
-1

只需键入将其转换为您想要的重载值

void method(int);
void method(string);
method((string) null){};

这将调用

于 2019-03-21T15:05:13.433 回答