选择不同的重载方法,具体取决于使用空参数调用它的位置

Posted

技术标签:

【中文标题】选择不同的重载方法,具体取决于使用空参数调用它的位置【英文标题】:Different overload method is chosen, depending from where it's called with a null parameter 【发布时间】:2017-07-01 10:35:38 【问题描述】:

我有一个具有重载 Format 方法的类。

 class FormatStuff
 
    public static string Format(object arg)
        => HandleObjectStuff();

    public static string Format(IEnumerable<object> args)
        => HandleListStuff();
 

现在,当我打电话时

FormatStuff.Format(null);

我以 IEnumerable 参数结束了第二次重载。 但就我而言,我从这样的函数中调用该方法:

 public static string DoStuff(IEnumerable<int> intnumerable)
 
     StringBuilder sb = new StringBuilder();
     sb.Append(FormatStuff.Format(intnumerable));
     return sb.ToString();
 

当我像这样调用这个函数时

DoStuff(null);

我在第一次重载时使用了单个对象参数,即使在这两种情况下都将 null 作为参数传递。

为什么会这样?我该怎么做才能在与 DoStuff 参数类型匹配的第二个重载中结束?

编辑: 该问题已被标记为可能与this one 重复。我不认为情况完全如此,因为帮助我理解我的问题的重点是,IEnumerable&lt;int&gt; 不是IEnumerable&lt;object&gt;。 一般来说,这意味着,不能指望任何类型的 IEnumerable 是对象的 IEnumerable,这是我不知道的。 上述帖子未得出此结论。

【问题讨论】:

IEnumerable&lt;int&gt; 不是 IEnumerable&lt;object&gt;,因此不适用过载。 那为什么我直接用FormatStuff.Format(null);调用Format函数的时候会出现IEnumerable重载呢? null 是一个IEnumerable&lt;object&gt;,它比object“更具体”,因此选择了重载。如果您使用IEnumerable&lt;int&gt; 调用Format,则仅适用object 重载。请参阅this answer,其中描述了如何解决重载问题。 Overloading null ambiguity的可能重复 【参考方案1】:

在编译时,每个调用表达式的调用(绑定)重载是静态固定的(除非您在编译时使用dynamic 类型)。仅仅因为您用于参数的表达式在程序运行时碰巧评估为另一种类型,重载不会神奇地改变。

例子:

FormatStuff.Format(null);

编译时类型不存在(null),但由于存在从 null 文字到 object 的隐式转换以及从 nullIEnumerable&lt;object&gt; 的隐式转换,因此这两个重载都是候选人。在这种情况下,IEnumerable&lt;object&gt; 的重载是首选,因为它更具体。

FormatStuff.Format((object)null);

在这种情况下,表达式的编译时类型是object,因此只应用了一个重载,并且使用了它。

IEnumerable<int> intnumerable
// ...
FormatStuff.Format(intnumerable);

在上述情况下,您传递的编译时类型是IEnumerable&lt;int&gt;。这里int 是一个值类型。 IEnumerable&lt;int&gt; 在编译时不是 IEnumerable&lt;object&gt;这是在编译时修复的; 在运行时intnumerable 是否恰好是null 无关紧要,如果非空,则实际类型(有些实现IEnumerable&lt;int&gt;) 的具体类或结构在运行时。

IEnumerable<string> strEnumerable
// ...
FormatStuff.Format(strEnumerable);

最后,在这种情况下,由于string 是一个引用类型,所以IEnumerable&lt;out T&gt; 的编译时协方差适用。所以IEnumerable&lt;string&gt; IEnumerable&lt;object&gt;。因此,两种重载都适用,并且首选最具体的重载。

【讨论】:

【参考方案2】:

要实现您想要的,您的方法必须能够区分两个方法调用。 当您传递 null 时,Format() 方法不知道您的 null 是 object 还是 IEnumerable&lt;object&gt;,因为两者都是对象类型。 要解决您的问题,您可以执行以下操作之一:

1 将第二种方法改为Format(IEnumerable&lt;int&gt; args)

2 通过添加可选参数来更改方法的类型签名。以this为例

【讨论】:

以上是关于选择不同的重载方法,具体取决于使用空参数调用它的位置的主要内容,如果未能解决你的问题,请参考以下文章

java 方法重载

什么是方法重载?可以定义两个同名但参数类型不同的方法吗?

方法的重载和重写

Java方法重载对象创建

重写和重载

方法的重载与重写