假设我有一个C#方法的两个重载版本:
void Method( TypeA a ) { }
void Method( TypeB b ) { }
我用以下方式调用该方法:
Method( null );
哪个方法的重载被调用了?我该怎么做才能确保调用特定的重载方法?
假设我有一个C#方法的两个重载版本:
void Method( TypeA a ) { }
void Method( TypeB b ) { }
我用以下方式调用该方法:
Method( null );
哪个方法的重载被调用了?我该怎么做才能确保调用特定的重载方法?
这取决于TypeA
和TypeB
。
null
到TypeB
没有转换因为它是值类型但TypeA
是引用类型),那么调用将被应用于适用的类型。TypeA
和TypeB
之间的关系。
TypeA
到TypeB
的隐式转换但没有从TypeB
到TypeA
的隐式转换,则使用使用TypeA
的重载。TypeB
到TypeA
的隐式转换但没有从TypeA
到TypeB
的隐式转换,则使用使用TypeB
的重载。有关详细规则,请参见C# 3.0规范的第7.4.3.4节。
以下是不会出现二义性情况的示例。这里TypeB
派生自TypeA
,意味着从TypeB
到TypeA
存在一个隐式转换,但反之则不然。因此使用使用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);
注意,如果这涉及到声明类的继承(即一个类正在重载其基类声明的方法),那么你就会遇到另一个问题,你需要转换方法的目标而不是参数。Jon Skeet给出了一份全面的答案,但从设计的角度来看,您不应该依赖于编译器规范的边缘情况。如果没有其他选择,在编写代码之前必须查找其含义,那么下一个尝试阅读它的人也将不知道它的含义。这是不可维护的。
重载方法是为了方便而存在的,同名的两个不同重载方法应该执行相同的操作。如果两个方法执行不同的操作,请重命名其中一个或两个都重命名。
通常,重载方法会有具有不同参数数量的变体,并且参数较少的重载方法会提供合理的默认值。
例如:string ToString(string format, System.IFormatProvider provider)
具有最多的参数,
string ToString(System.IFormatProvider provider)
提供默认格式,和
string ToString()
提供默认格式和提供程序。
Jon Skeet已经回答了默认情况下会选择哪个重载函数,但是如果你想确保调用特定的重载函数,通常最好使用命名参数而不是转换。
如果你有以下代码:
void Method( TypeA a ) { }
void Method( TypeB b ) { }
Method(a: null);
或 Method(b: null);
。模糊的调用。(编译时错误)。
class Program
{
void test1(IList a)
{
Console.WriteLine("test1-List");
}
void test1(IComparer a)
{
Console.WriteLine("test1-IComparer");
}
static void Main(string[] args)
{
Program p = new Program();
p.test1(null);
Console.ReadKey();
}
}
- Krishna Kumarvoid Method() { }
或者最好更新其中一个方法的签名为:
void Method( TypeB b = null ) { }
然后这样调用:
Method();
在编译时,值 null
是未命名的,因此编译器无法将其与其中一个方法签名匹配。 在运行时,任何可能解析为 null
的变量仍将被分配类型,因此不会引起问题。
只需将其强制转换为您想要的重载值即可
void method(int);
void method(string);
method((string) null){};
这将调用