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

时间:2014-06-03 09:42:37

标签: 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)
    {

    }    
}

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

  

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

我的猜测是在longdecimal之间进行了一些隐式转换,但有没有人知道我可能做错了什么?有没有解决方法?

3 个答案:

答案 0 :(得分:6)

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

Section 7.4.2.3

  

[...]

     

否则,转换都不会更好。

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


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

TestDecimal

对于一种情况,这种方式在重载解析期间不需要隐式转换(因为在转换new Test(new Action<decimal>(TestDecimal)) 类型之后将完全匹配),而另一种情况则必须转换为Action<T> Action<long>),以及上面提到的部分说明:

  

[...]

     

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

     

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

     

[...]

答案 1 :(得分:1)

这是由于长和十进制之间的隐式转换。

这里是C#(Picture Source)中隐式铸件(简单类型)的表格:

enter image description here

详细了解类型转化here

答案 2 :(得分:1)

有一种解决方法:

    Test t = new Test(new Action<decimal>(TestDecimal));