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

eis*_*ony 6 c#

希望有人可以向我解释这一点.对不起,如果这是重复的话,解释我所看到的内容的关键词现在已超出我的范围了.

这里有一些编译的代码

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

这里有一些代码没有

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

通过添加构造函数重载,这显然会产生歧义,但我不确定为什么.Math.Sqrt没有重载,显然返回类型为double,而不是Task <double>.

这是错误:

以下方法或属性之间的调用不明确:'ConsoleApplication1.Transformer <double,double> .Transformer(System.Func <double,double>)'和'ConsoleApplication1.Transformer <double,double> .Transformer(System.Func <双,System.Threading.Tasks.Task <双>>)"

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


易于解决的问题:

class Program
{
    static void Main(string[] args)
    {
        new Transformer<double, double>(d => Math.Sqrt(d));
    }
}
Run Code Online (Sandbox Code Playgroud)

Jer*_*vel 6

你对如何Func<Tin, Tout>运作有轻微的误解.看看文档:

public delegate TResult Func<in T, out TResult>(
    T arg
)
Run Code Online (Sandbox Code Playgroud)

第一个参数是参数,最后一个参数是返回类型.

当您查看代码的简化版本时:

internal class Program
{
    public static void Main(string[] args)
    {
        new MyClass<double, double>(Method);
    }

    private static double Method(double d)
    {
        throw new NotImplementedException();
    }
}


internal class MyClass<T, U>
{
    public MyClass(Func<U, T> arg)
    {
    }

    public MyClass(Func<U, Task<T>> arg)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

你会注意到两个参数首先指定double,这是一个参数,然后在返回类型上有所不同:Tvs Task<T>.

但是我们都知道:重载是基于方法名称,参数arity和参数类型完成的.返回类型完全被忽略.在我们的例子中,这意味着我们有两个Func<Tin, Tout>double作为参数和TVS Task<T>的返回类型.

切换参数编译就好了:

internal class MyClass<T, U>
{
    public MyClass(Func<T, U> arg)
    {
    }

    public MyClass(Func<Task<T>, U> arg)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您将在Visual Studio中查看,您会注意到此方法现在变为灰色,这是有道理的,因为参数Method是类型的double,因此总是匹配T而不是Task<T>.

因此,为了测试它是否会在传递不同的异步方法时达到正确的重载,您可以添加第二种方法:

private static double MethodAsync(Task<double> d)
{
   throw new NotImplementedException();
}
Run Code Online (Sandbox Code Playgroud)

并使用它来调用它

new MyClass<double, double>(MethodAsync);
Run Code Online (Sandbox Code Playgroud)

您现在将注意到异步Func<Task<T>, U>>被命中(您可以通过从构造函数中简单地打印到控制台来验证).


简而言之:您尝试在返回类型上执行重载解析,这显然是不可能的.