希望有人可以向我解释。对不起,如果重复一遍,那么解释我所看到的内容的关键词现在已超出我的范围了。
这里有一些编译
的代码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));
}
}
这里有一些不是
的代码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;
}
}
通过添加构造函数重载,这显然会产生歧义,但我不确定原因。 Math.Sqrt没有重载,显然返回类型为double,而不是Task&lt; double&gt ;.
这是错误:
以下方法或属性之间的调用不明确:&#39; ConsoleApplication1.Transformer&lt; double,double&gt; .Transformer(System.Func&lt; double,double&gt;)&#39;和&#39; ConsoleApplication1.Transformer&lt; double,double&gt; .Transformer(System.Func&lt; double,System.Threading.Tasks.Task&lt; double&gt;&gt;)&#39;
有人可以解释为什么选择对编译器来说不明显吗?
为那些关心的人提供简单的解决方法:
class Program
{
static void Main(string[] args)
{
new Transformer<double, double>(d => Math.Sqrt(d));
}
}
答案 0 :(得分:5)
您对Func<Tin, Tout>
的工作方式略有误解。看看the docs:
public delegate TResult Func<in T, out TResult>(
T arg
)
第一个参数是参数,最后一个参数是返回类型。
当您查看代码的简化版本时:
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)
{
}
}
您会注意到两个参数首先指定double
,这是一个参数,然后返回类型不同:T
vs Task<T>
。
但是我们都知道:重载是基于方法名称,参数arity和参数类型完成的。返回类型完全被忽略。在我们的情况下,这意味着我们有两个Func<Tin, Tout>
以double
作为参数,T
与Task<T>
作为返回类型。
切换参数编译就好了:
internal class MyClass<T, U>
{
public MyClass(Func<T, U> arg)
{
}
public MyClass(Func<Task<T>, U> arg)
{
}
}
如果您在Visual Studio中查看,您会注意到此方法现在变为灰色,这是有道理的,因为Method
的参数属于double
类型,因此将始终与T
匹配,而不是Task<T>
。
因此,为了测试它是否会在传递不同的异步方法时遇到正确的重载,您可以添加第二种方法:
private static double MethodAsync(Task<double> d)
{
throw new NotImplementedException();
}
并使用
调用它new MyClass<double, double>(MethodAsync);
现在您将注意到异步Func<Task<T>, U>>
已被命中(您可以通过从构造函数中简单地打印到控制台来验证)。
简而言之:您尝试在返回类型上执行重载解析,这显然是不可能的。