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

发布于 2024-07-17 09:00:00 字数 211 浏览 8 评论 0原文

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

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

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

Method( null );

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

Say I have two overloaded versions of a C# method:

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

I call the method with:

Method( null );

Which overload of the method is called? What can I do to ensure that a particular overload is called?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

瘫痪情歌 2024-07-24 09:00:00

它取决于 TypeATypeB

  • 如果其中一个适用(例如,没有从 nullTypeB 的转换,因为它是值类型,但 TypeA 是引用类型)然后将呼叫相应的人。
  • 否则,取决于 TypeATypeB 之间的关系。
    • 如果存在从 TypeATypeB 的隐式转换,但没有从 TypeBTypeA 的隐式转换,则将使用使用 TypeA 的重载。
    • 如果存在从 TypeBTypeA 的隐式转换,但没有从 TypeATypeB 的隐式转换,则将使用使用 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);

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

It depends on TypeA and TypeB.

  • If exactly one of them is applicable (e.g. there is no conversion from null to TypeB because it's a value type but TypeA is a reference type) then the call will be made to the applicable one.
  • Otherwise it depends on the relationship between TypeA and TypeB.
    • If there is an implicit conversion from TypeA to TypeB but no implicit conversion from TypeB to TypeA then the overload using TypeA will be used.
    • If there is an implicit conversion from TypeB to TypeA but no implicit conversion from TypeA to TypeB then the overload using TypeB will be used.
    • Otherwise, the call is ambiguous and will fail to compile.

See section 7.4.3.4 of the C# 3.0 spec for the detailed rules.

Here's an example of it not being ambiguous. Here TypeB derives from TypeA, which means there's an implicit conversion from TypeB to TypeA, but not vice versa. Thus the overload using TypeB is used:

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

In general, even in the face of an otherwise-ambiguous call, to ensure that a particular overload is used, just cast:

Foo((TypeA) null);

or

Foo((TypeB) null);

Note that if this involves inheritance in the declaring classes (i.e. one class is overloading a method declared by its base class) you're into a whole other problem, and you need to cast the target of the method rather than the argument.

ㄟ。诗瑗 2024-07-24 09:00:00

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

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

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

例如 string ToString(string format, System.IFormatProviderprovider) 参数最多,
string ToString(System.IFormatProviderprovider) 提供默认格式,并且
string ToString() 提供默认格式和提供程序,

Jon Skeet has given a comprehensive answer, but from a design point of view you shouldn't depend on corner-cases of the compiler specification. If nothing else, if you have to look up what it does before you write it, the next person to try to read it won't know what it does either. It's not maintainable.

Overloads are there for convenience, and two different overloads with the same name should do the same thing. If the two methods do different things, rename one or both of them.

It's more usual for an overloaded method to have variants with varying numbers of parameters, and for the overload with less parameters to supply sensible defaults.

e.g. string ToString(string format, System.IFormatProvider provider) has the most parameters,
string ToString(System.IFormatProvider provider) supplies a default format, and
string ToString() supplies a default format and provider,

叫思念不要吵 2024-07-24 09:00:00

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

如果有:

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

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

Jon Skeet already answered which overload gets chosen by default, but if you want to ensure that particular overload is called, it is often better to use named parameters than cast.

If you have:

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

You can call Method(a: null); or Method(b: null);

如此安好 2024-07-24 09:00:00

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

ambigous call. (compile time error).

旧城烟雨 2024-07-24 09:00:00

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

void Method() { }

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

void Method( TypeB b = null ) { }

然后按如下方式调用它:

Method();

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

A simple solution is to create another method with the signature of:

void Method() { }

or better to update the signature on one of the methods to be:

void Method( TypeB b = null ) { }

and then call it as so:

Method();

At compile time the value null is untyped and so the compiler can't match it up with one of the method signatures. At run time any variable that might resolve to null will still be typed and so it won't cause a problem.

雾里花 2024-07-24 09:00:00

只需将其类型转换为您想要的重载值,

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

这将调用

Just type cast it to what you want the overloaded value to be

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

This will call the

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文