方法重载决策系统如何决定在传递空值时调用哪个方法?

时间:2011-03-02 20:56:08

标签: c# .net overload-resolution

例如,您有类似的类型:

public class EffectOptions
{
    public EffectOptions ( params object [ ] options ) {}

    public EffectOptions ( IEnumerable<object> options ) {}

    public EffectOptions ( string name ) {}

    public EffectOptions ( object owner ) {}

    public EffectOptions ( int count ) {}

    public EffectOptions ( Point point ) {}

}

这里我只使用构造函数给出示例,但如果它们是类型本身的非构造函数方法,结果将是相同的,对吧?

所以当你这样做时:

EffectOptions options = new EffectOptions (null);

将调用哪个构造函数,为什么?

我可以自己测试一下,但我想了解重载分辨率系统是如何工作的(不确定这是否就是它的名称)。

2 个答案:

答案 0 :(得分:76)

有关具体规则,请参阅the overload resolution spec。但简而言之,就是这样。

首先,列出所有可访问的构造函数。

public EffectOptions ( params object [ ] options )
public EffectOptions ( IEnumerable<object> options ) 
public EffectOptions ( string name )
public EffectOptions ( object owner ) 
public EffectOptions ( int count ) 
public EffectOptions ( Point point )

接下来,删除所有不适用的构造函数。适用的构造函数是每个形式参数都有相应参数的构造函数,并且参数可以隐式转换为形式参数类型。假设Point是值类型,我们消除了“int”和“Point”版本。离开

public EffectOptions ( params object[] options )
public EffectOptions ( IEnumerable<object> options ) 
public EffectOptions ( string name )
public EffectOptions ( object owner ) 

现在,我们必须考虑具有“params”的那个是否适用于其扩展未展开形式。在这种情况下,它适用于两种形式。当发生这种情况时,我们会丢弃展开的表单。离开

public EffectOptions ( object[] options )
public EffectOptions ( IEnumerable<object> options ) 
public EffectOptions ( string name )
public EffectOptions ( object owner ) 

现在我们必须确定适用候选人的最佳。最佳性规则很复杂,但简短版本是更具体,优于不太具体。长颈鹿比哺乳动物更具特异性,哺乳动物比动物更具特异性,动物比对象更具体。

object版本的具体程度低于所有版本,因此可以将其删除。 IEnumerable<object>版本的特定性不如object[]版本(您知道为什么?)因此也可以将其删除。离开

public EffectOptions ( object[] options )
public EffectOptions ( string name )

现在我们被困住了。 object[]并不比string更具特异性。因此,这会产生歧义错误。

这只是一个简短的草图;真正的tiebreaking算法要复杂得多。但这些都是基础。

答案 1 :(得分:7)

在这种情况下,C#编译器不会选择任何构造函数,而是会出错。值null对于几个可用的构造函数是合法的,并且没有足够的打破平局逻辑来选择一个因此它产生错误。

C#编译器重载决策逻辑是一个复杂的过程,但对其工作方式的简短(并且本质上不完整)概述如下

  • 收集具有指定姓名的所有成员
  • 将成员过滤为具有与提供的参数兼容且具有相应辅助功能的参数列表的成员
  • 如果其余成员有多个元素,请使用打破平局逻辑来选择最佳成员

完整的详细信息在C#语言规范的第7.4节中列出。而且我确信埃里克很快就会提供更准确的描述:)