将方法组作为委托传递时,C#调用是不明确的

将方法组作为委托传递时,C#调用是不明确的,c#,C#,希望有人能给我解释一下。抱歉,如果这是重复的话,我现在无法用关键词来解释我所看到的 下面是一些编译的代码 class Program { static void Main(string[] args) { new Transformer<double, double>(Math.Sqrt); } } class Transformer<Tin, Tout> { Func<Tin, Task<Tout>&g

希望有人能给我解释一下。抱歉,如果这是重复的话,我现在无法用关键词来解释我所看到的

下面是一些编译的代码

class Program
{
    static void Main(string[] args)
    {
        new Transformer<double, double>(Math.Sqrt);
    }
}

class Transformer<Tin, Tout>
{
    Func<Tin, Task<Tout>> actor;
    public Transformer(Func<Tin, Tout> actor)
    {
        this.actor = input => Task.Run<Tout>(() => actor(input));
    }
}
类程序
{
静态void Main(字符串[]参数)
{
新变压器(数学Sqrt);
}
}
类变压器
{
扮演者;
公共变压器(功能参与者)
{
this.actor=input=>Task.Run(()=>actor(input));
}
}
这里有一些代码没有

class Program
{
    static void Main(string[] args)
    {
        new Transformer<double, double>(Math.Sqrt);
    }
}

public class Transformer<Tin, Tout>
{
    Func<Tin, Task<Tout>> actor;
    public Transformer(Func<Tin, Tout> actor)
    {
        this.actor = input => Task.Run<Tout>(() => actor(input));
    }

    public Transformer(Func<Tin, Task<Tout>> actor)
    {
        this.actor = actor;
    }
}
类程序
{
静态void Main(字符串[]参数)
{
新变压器(数学Sqrt);
}
}
公共级变压器
{
扮演者;
公共变压器(功能参与者)
{
this.actor=input=>Task.Run(()=>actor(input));
}
公共变压器(功能参与者)
{
这个演员=演员;
}
}
通过添加构造函数重载,这显然会产生歧义,但我不知道为什么。Sqrt没有重载,显然它的返回类型是double,而不是Task

以下是错误:

以下方法或属性之间的调用不明确:'ConsoleApplication1.Transformer.Transformer(System.Func)'和'ConsoleApplication1.Transformer.Transformer(System.Func)'

有人能解释为什么选择对编译器来说不明显吗


为关心这些问题的人提供简单的解决方法:

class Program
{
    static void Main(string[] args)
    {
        new Transformer<double, double>(d => Math.Sqrt(d));
    }
}
类程序
{
静态void Main(字符串[]参数)
{
新变压器(d=>Math.Sqrt(d));
}
}

您对
Func
的工作原理有一点误解。看看:

如果您在Visual Studio中查看,您会注意到此方法现在变灰,这是有意义的,因为
method
的参数类型为
double
,因此始终匹配
T
,而不是
Task

因此,为了测试如果传入不同的异步方法,它现在是否会遇到正确的重载,可以添加第二个方法:

private static double MethodAsync(Task<double> d)
{
   throw new NotImplementedException();
}
private static double MethodAsync(任务d)
{
抛出新的NotImplementedException();
}
并称之为使用

new MyClass<double, double>(MethodAsync);
newmyclass(MethodAsync);
现在您将注意到异步
Func>
被命中(您可以通过从构造函数执行简单的print to console来验证)



简而言之:您试图对返回类型执行重载解析,这显然是不可能的。

顺便说一句,还有另一个解决方法:
newtransformer((Func)Math.Sqrt)可能是一个bug。我自己也经历过几次类型推断的极限,也见过类似的失败。我来告诉你真正可怕的是什么——你没有把构造函数调用链接在一起。啧啧<代码>公共转换器(Func-actor):这个(输入=>Task.Run(()=>actor(输入))
。我怀疑这会解决问题,但它会防止不幸的错误@虽然这(显然,我希望)是一个简单的重述,但我会给出公正的评论。实际上,我在Microsoft Dataflow()类上看到了这种行为:TransformBlock等。有关编译器需要显式键入委托(如@Szer所建议)的简单解释,请参阅。嗯。。我还是没得到什么。模糊性取决于具有不同参数的构造函数。Math.Sqrt没有歧义——只有一个选项。根据您的回答,这不应该导致正确的解决方案吗?@eisenpony:Math.Sqrt中没有歧义——而是在构造函数的Func参数中。您说它们接受不同的参数,但它们不接受:它们接受不同的返回类型,但参数相同。在这种情况下,构造函数似乎采用了不同的参数,但您必须深入研究。首先,它匹配一个Func和一个double,然后找到它。然后它在Func内部查看它必须使用哪一个,它发现两个Func具有相同的参数,但返回类型不同,所以它被卡住了。好的,我明白了。我不是建议Func使用不同的参数,我认为构造函数使用不同的参数。然而,从编译器的角度来看,您所说的Func是彼此无法区分的,这是有道理的。这是编译器的正常行为,因为当您正常调用方法时,不可能预测预期的返回类型。但是,在这种情况下,编译器似乎可以使用返回类型作为其解析的一部分,因为Math.Sqrt.method组中只有一种可能的返回类型:double。
internal class MyClass<T, U>
{
    public MyClass(Func<T, U> arg)
    {
    }

    public MyClass(Func<Task<T>, U> arg)
    {
    }
}
private static double MethodAsync(Task<double> d)
{
   throw new NotImplementedException();
}
new MyClass<double, double>(MethodAsync);