Mic*_*ett 18 c# asynchronous tap
作为.NET 4.5一部分的新Task.Run静态方法似乎没有像人们期望的那样运行.
例如:
Task<Int32> t = Task.Run(()=>5);
Run Code Online (Sandbox Code Playgroud)
编译好,但是
Task<Int32> t = Task.Run(MyIntReturningMethod);
...
public Int32 MyIntReturningMethod() {
return (5);
}
Run Code Online (Sandbox Code Playgroud)
抱怨MyIntReturningMethod返回了错误的类型.
也许我只是不了解正在调用Task.Run的哪个重载.但在我看来,我上面的lambda代码看起来很像Func<Int32>,而且MyIntReturningMethod绝对兼容Func<Int32>
对于发生了什么的任何想法?迈克尔
Jep*_*sen 11
(当然,要解决问题,简单地说Task.Run((Func<int>)MyIntReturningMethod).)
这与完全无关Task等等.
这里需要注意的一个问题是,当存在很多重载时,编译器错误文本将只关注一对"重载".所以这很令人困惑.原因是确定最佳过载的算法考虑了所有重载,并且当该算法断定没有找到最佳过载时,不会产生错误文本的某对重载,因为所有重载都可能(或可能不)参与过.
要了解会发生什么,请参阅此简化版本:
static class Program
{
static void Main()
{
Run(() => 5); // compiles, goes to generic overload
Run(M); // won't compile!
}
static void Run(Action a)
{
}
static void Run<T>(Func<T> f)
{
}
static int M()
{
return 5;
}
}
Run Code Online (Sandbox Code Playgroud)
正如我们所看到的,这绝对没有参考Task,但仍然会产生同样的问题.
请注意,匿名函数转换和方法组转换(仍)不完全相同.详细信息可在C#语言规范中找到.
lambda:
() => 5
Run Code Online (Sandbox Code Playgroud)
实际上甚至不能转换为System.Action类型.如果您尝试这样做:
Action myLittleVariable = () => 5;
Run Code Online (Sandbox Code Playgroud)
它将失败并出现错误CS0201:只能将赋值,调用,递增,递减,等待和新对象表达式用作语句.因此很清楚与lambda一起使用哪个重载.
另一方面,方法组:
M
Run Code Online (Sandbox Code Playgroud)
是可转换为Func<int>和Action.请记住,完全允许不接收返回值,就像语句一样:
M(); // don't use return value
Run Code Online (Sandbox Code Playgroud)
本身是有效的.
这种方式回答了这个问题,但我会举一个额外的例子来说明一个问题.考虑这个例子:
static class Program
{
static void Main()
{
Run(() => int.Parse("5")); // compiles!
}
static void Run(Action a)
{
}
static void Run<T>(Func<T> f)
{
}
}
Run Code Online (Sandbox Code Playgroud)
在最后一个示例中,lambda实际上可以转换为两种委托类型!(只是尝试删除泛型重载.)对于lambda箭头的右侧=>是一个表达式:
int.Parse("5")
Run Code Online (Sandbox Code Playgroud)
这本身就是一个有效的声明.但是在这种情况下,重载分辨率仍然可以找到更好的过载.正如我之前所说,检查C#规范.
受HansPassant和BlueRaja-DannyPflughoeft的启发,这是最后一个(我认为)的例子:
class Program
{
static void Main()
{
Run(M); // won't compile!
}
static void Run(Func<int> f)
{
}
static void Run(Func<FileStream> f)
{
}
static int M()
{
return 5;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,在这种情况下,绝对没有办法int 5可以转换为System.IO.FileStream.方法组转换仍然失败.这可能与两个普通的方法其实int f();和FileStream f();,例如通过从两个不同的基本接口部分接口继承,就没有办法解决了通话f();.返回类型不是C#中方法签名的一部分.
我仍然避免Task在我的回答中介绍,因为它可能会给出这个问题的错误印象.人们很难理解Task,而且它在BCL中相对较新.
这个答案已经发展了很多.最后,事实证明,这与线程中的底层问题真的相同为什么Func<T>不明确Func<IEnumerable<T>>?.我的例子Func<int>和Func<FileStream>几乎一样清楚.Eric Lippert在其他帖子中给出了一个很好的答案.
这应该在.Net 4.0中修复,但Task.Run()是.Net 4.5的新功能
通过添加Task.Run(Func<Task<T>>)方法,.NET 4.5有自己的重载歧义.并支持在C#版本5中的async/await.它允许隐式转换T foo()为Func<Task<T>>.
这是async/await非常甜的语法糖,但在这里会产生空洞.在方法重载中没有考虑async方法声明中关键字的遗漏,这会打开另一个苦差事框,程序员忘记在他们意图使用异步时.否则遵循通常的C#约定,只考虑方法签名中的方法名称和参数进行方法重载选择.
需要显式使用委托类型来解决歧义.
看起来像是一个重载解决问题。编译器无法判断您正在调用哪个重载(因为首先它必须找到要创建的正确委托,但它不知道该委托,因为这取决于您正在调用的重载)。它必须猜测并检查,但我猜它不是那么聪明。
| 归档时间: |
|
| 查看次数: |
3953 次 |
| 最近记录: |