当我遇到这种特殊情况时,我正在实现同步/异步重载:
当我有一个没有参数或返回值的常规lambda表达式时,它会Run使用Action参数进行重载,这是可预测的.但是当lambda中有一个lambda时,while (true)它会通过Func参数进入重载状态.
public void Test()
{
Run(() => { var name = "bar"; });
Run(() => { while (true) ; });
}
void Run(Action action)
{
Console.WriteLine("action");
}
void Run(Func<Task> func) // Same behavior with Func<T> of any type.
{
Console.WriteLine("func");
}
Run Code Online (Sandbox Code Playgroud)
输出:
动作
功能
那怎么可能呢?有原因吗?
如果我有一个像() => { throw new Exception(); }这样的lambda ,则不清楚它是否有返回类型.因此,它可以(隐式)转换为Action和Func<object>(或任何其他Func<T>).这是因为,根据§6.5C #4规范的匿名函数转换:
[A]委托类型
D与提供的匿名功能兼容F:
...
如果
D有一个void返回类型且bodyF是一个语句块,当[...]的主体F是一个有效的语句块时,其中没有return语句指定一个表达式.如果
D具有非void返回类型且bodyF是一个语句块,则当[...]主体F是具有不可到达端点的有效语句块时,其中每个return语句指定一个可隐式转换为返回的表达式的类型D.
但是如果我有一个方法的两个重载,其中一个具有类型的参数Action和另一个Func<object>,并且我从上面传递lambda,Func<object>则使用重载.为什么?规范的哪一部分说Func<object>比Action这种情况更好?
我已经看过§7.5.3.2 更好的函数成员,但这并没有解释它.
在这种情况下预期的是,如果用户通过按Enter键取消任务,则挂起的另一个任务ContinueWith将运行,但事实并非如此,AggregateException尽管显式处理ContinueWith显然没有被执行,但仍保持抛出.
请问下面的任何澄清?
class Program
{
static void Main(string[] args)
{
CancellationTokenSource tokensource = new CancellationTokenSource();
CancellationToken token = tokensource.Token;
Task task = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
Console.Write("*");
Thread.Sleep(1000);
}
}, token).ContinueWith((t) =>
{
t.Exception.Handle((e) => true);
Console.WriteLine("You have canceled the task");
}, TaskContinuationOptions.OnlyOnCanceled);
Console.WriteLine("Press any key to cancel");
Console.ReadLine();
tokensource.Cancel();
task.Wait();
}
}
Run Code Online (Sandbox Code Playgroud) .net c# multithreading task-parallel-library cancellation-token
我的同事玩TPL并取消任务.他向我展示了以下代码:
var cancellationToken = cts.Token;
var task = Task.Run(() =>
{
while (true)
{
Thread.Sleep(300);
if (cancellationToken.IsCancellationRequested)
{
throw new OperationCanceledException();
}
}
}, cancellationToken)
.ContinueWith(t => {
Console.WriteLine(t.Status);
});
Thread.Sleep(200);
cts.Cancel();
Run Code Online (Sandbox Code Playgroud)
这版画"取消"符合市场预期,但如果你只是发表评论,而像这样的一行:
// ..
//while (true)
{
Thread.Sleep(300);
if (cancellationToken.IsCancellationRequested)
{
throw new OperationCanceledException();
}
}
//..
Run Code Online (Sandbox Code Playgroud)
你会得到"故障".我很清楚ThrowIfCancellationRequested()方法,我应该在OperationCanceledException的构造函数中传递cancellationToken(在这两种情况下都会导致"取消"结果),但无论如何我无法解释为什么会发生这种情况.