37

因此,例如,您有如下类型:

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

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

我可以自己对此进行测试,但我想了解重载解决系统是如何工作的(不确定这是否就是所谓的)。

4

2 回答 2

83

有关确切的规则,请参阅重载决议规范。但简而言之,它是这样的。

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

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。因此,这会产生歧义错误。

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

于 2011-03-02T23:20:58.207 回答
9

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

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

  • 收集具有给定名称的所有成员
  • 将成员筛选为具有与提供的参数兼容且具有适当可访问性的参数列表的成员
  • 如果其余成员有多个元素,则使用平局逻辑来选择其中最好的

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

于 2011-03-02T20:59:00.390 回答