使用Action <T>参数重载调用不明确的方法

dea*_*ull 6 c# ambiguity overload-resolution

我在调用具有不同Action<T>变体的重载方法时遇到了一些意外的编译器行为.

假设我有这个类Test,我在CallTest构造函数中创建它的实例.

public class Test
{
    public Test(Action<long> arg)
    {

    }

    public Test(Action<decimal> arg)
    {

    }
}

public class CallTest
{
    public CallTest()
    {
        Test t = new Test(TestDecimal);
    }

    public void TestDecimal(decimal arg)
    {

    }

    public void TestLong(long arg)
    {

    }    
}
Run Code Online (Sandbox Code Playgroud)

Test使用TestDecimalTestLong作为参数调用构造函数时,我收到以下错误:

以下方法或属性之间的调用不明确:' Test(System.Action<long>)'和' Test(System.Action<decimal>)'

我的猜测是有一些隐式转换之间正在进行的longdecimal,但没有任何人有任何其他想法可能我做错?有没有解决方法?

Bar*_*zKP 6

当您传递TestDecimalTestLong作为参数时,您实际上正在传递方法组(毕竟,可能有多个TestDecimal方法 - 它可能已经过载).因此,在这两种情况下都会发生隐式转换 - 从方法组到特定委托类型.因此,这两种方法都适用于候选者(第7.4.2节).从适用的候选者中,重载决策算法试图找到最佳候选者.但是,在匹配参数列表状态时比较转换的规则,如果两个候选隐式转换都发生,则两者都不是更好:

第7.4.2.3节:

[...]

否则,转换都不会更好.

这就是为什么在你的情况下存在歧义.


解决方法当然是首先明确地转换参数:

new Test(new Action<decimal>(TestDecimal))
Run Code Online (Sandbox Code Playgroud)

这样一情况下,将过载解析过程中不需要隐式转换(如铸造后Action<T>类型将完全匹配),另将不得不被转换(Action<long>Action<decimal>),以及上面提到的部分指出:

[...]

如果S是T1,则C1是更好的转换.

如果S是T2,则C2是更好的转换.

[...]