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

SWB*_*SWB 34 c# null overloading

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

void Method( TypeA a ) { }
void Method( TypeB b ) { }
Run Code Online (Sandbox Code Playgroud)

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

Method( null );
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*eet 71

这取决于TypeATypeB.

  • 如果其中只有一个适用(例如,没有转换null,TypeB因为它是值类型但是TypeA引用类型),那么将调用适用的那个.
  • 否则它取决于TypeA和之间的关系TypeB.
    • 如果存在隐式转换TypeA,TypeB但没有隐式转换TypeB,TypeA那么TypeA将使用重载使用.
    • 如果存在隐式转换TypeB,TypeA但没有隐式转换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)
    }
}
Run Code Online (Sandbox Code Playgroud)

一般来说,即使面对其他模糊的调用,为了确保使用特定的重载,只需转换:

Foo((TypeA) null);
Run Code Online (Sandbox Code Playgroud)

要么

Foo((TypeB) null);
Run Code Online (Sandbox Code Playgroud)

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

  • @divo:这绝对是一个设计决策,但可能背后的原因是TypeB方法几乎是TypeA方法的一个特例.我的意思是,对于每个有效的arg,默认情况下TypeA将匹配,除非已知该对象是TypeB.null的此行为可确保此一致性. (2认同)

Ant*_*ony 8

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

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

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

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


小智 5

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

如果你有:

void Method( TypeA a ) { }
void Method( TypeB b ) { }
Run Code Online (Sandbox Code Playgroud)

你可以打电话Method(a: null);Method(b: null);