C#:将null传递给重载的方法 – 调用哪个方法?

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

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

我将这个方法称为:

 Method( null ); 

该方法的哪个重载被调用? 我能做些什么来确保一个特定的超载被称为?

这取决于TypeATypeB

  • 如果其中只有一个是适用的(例如,没有从nullTypeB转换,因为它是一个值types,但是TypeA是一个引用types),那么将调用适用的。
  • 否则,它取决于TypeATypeB之间的关系。
    • 如果存在从TypeATypeB的隐式转换,但没有从TypeBTypeA隐式转换,则将使用使用TypeA的重载。
    • 如果存在从TypeBTypeA的隐式转换,但没有从TypeATypeB隐式转换,则将使用使用TypeB的重载。
    • 否则,调用不明确,将无法编译。

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

这是一个不含糊的例子。 这里TypeBTypeA派生的,这意味着TypeBTypeA有一个隐式的转换,反之则不然。 因此,使用TypeB的过载被使用:

 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); 

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

Jon Skeet给出了一个全面的答案,但是从devise的angular度来看,你不应该依赖于编译器规范的angular落案例。 如果没有其他的东西,如果你在写它之前必须查看它做了什么,下一个尝试阅读它的人将不知道它做了什么。 这是不可维护的。

重载是为了方便,两个同名的重载应该做同样的事情。 如果这两种方法做不同的事情,重命名一个或两个。

对于重载方法来说,更多的variables具有不同数量的参数,而对于具有较less参数的重载来提供合理的默认值更为常见。

例如string ToString(string format, System.IFormatProvider provider)具有最多的参数,
string ToString(System.IFormatProvider provider)提供默认格式,并
string ToString()提供一个默认的格式和提供者,

Jon Skeet已经回答了默认情况下select哪个重载,但是如果你想确保调用特定的重载,通常使用命名参数比cast更好。

如果你有:

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

你可以调用Method(a: null);Method(b: null);

ambigous电话。 (编译时错误)。

一个简单的解决scheme是创build另一个签名为:

 void Method() { } 

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

 void Method( TypeB b = null ) { } 

然后像这样调用它:

 Method(); 

在编译时, null的值是无types的,所以编译器不能和其中一个方法签名匹配。 在运行时,任何可能parsing为nullvariables仍将被键入,因此不会导致问题。