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

时间:2009-04-05 19:42:04

标签: c# null overloading

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

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

我用以下方法调用方法:

Method( null );

调用该方法的哪个重载?我该怎么做才能确保调用特定的重载?

6 个答案:

答案 0 :(得分:71)

取决于TypeATypeB

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

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

这是一个不模糊的例子。此处TypeB来自TypeA,这意味着存在从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);

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

答案 1 :(得分:8)

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

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

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

e.g。 string ToString(string format, System.IFormatProvider provider)参数最多,
string ToString(System.IFormatProvider provider)提供默认格式,并且
string ToString()提供默认格式和提供商

答案 2 :(得分:4)

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

如果你有:

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

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

答案 3 :(得分:1)

暧昧的电话。 (编译时错误)。

答案 4 :(得分:0)

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

void Method() { }

或更好地更新其中一个方法的签名:

void Method( TypeB b = null ) { }

然后将其称为:

Method();

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

答案 5 :(得分:-1)

只需将其强制转换为您想要的重载值即可

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

这将称为