C# 等待抽象异步任务
我对C# 等待抽象异步任务,c#,async-await,task,abstract,C#,Async Await,Task,Abstract,我对async/await用法非常陌生。我试图抽象异步,并在UI中有条件地等待。我有一个抽象基类: public abstract class Base { public abstract bool IsRunning { get; } public abstract Task<bool> Run(); } 希望这是清楚的。我是否可以执行上述操作,特别是在if块内有条件地等待?理想情况下,对于Run方法,我想让Base类只返回bool而不是Task,并且只让Deri
async/await
用法非常陌生。我试图抽象异步,并在UI中有条件地等待。我有一个抽象基类:
public abstract class Base
{
public abstract bool IsRunning { get; }
public abstract Task<bool> Run();
}
希望这是清楚的。我是否可以执行上述操作,特别是在if块内有条件地等待?理想情况下,对于Run
方法,我想让Base
类只返回bool
而不是Task
,并且只让Derived2
类重写来返回任务
,但我不清楚如何做。也许我应该在Derived2
的Run
方法中返回task.Result
?如果有更好的方法,包括抽象或任何其他更正,请让我知道。谢谢你的建议
编辑#1
Derived1
中同步实现的Run
方法表单已在下面的响应中阐明。但是,我不允许更改DoSomething
方法的签名,因此考虑到Derived2
(异步实现)中我的Run
方法现在看起来如下(感谢@Stripling的注释):
我不知道您的同步版本是如何同步的,您仍然使用
任务。Run(
),这是我所期望的
internal class Derived1 : Base
{
private readonly Base baseCase;
private Task<bool> task;
public Derived1(Base baseCase)
{
this.baseCase = baseCase;
}
public override bool IsRunning
{
get { return false; }
}
public override Task<bool> Run()
{
bool ok = DoSomething();
return Task.FromResult(ok);
}
}
异步版本将异步运行,同步版本将同步运行
您的“异步版本”也不是真正的异步版本,请参阅以了解执行该方法的正确方法
我是否可以执行上述操作,特别是在if块内有条件地等待
可以,但不必。如果你做得对,以阻塞方式专门调用同步任务没有什么好处:一般来说,你可以等待返回的任务,如果它代表一个同步任务,wait
将以非常小的代价同步解析头顶
当我说“如果你做对了事情”,以下是正确的方式:
// synchronous
public override Task<bool> Run()
{
var result = DoSomething();
return Task.FromResult(result);
}
// asynchronous
public override async Task<bool> Run()
{
var result = await DoSomethingAsync();
return result;
}
//同步
公共覆盖任务运行()
{
var结果=剂量测量();
返回Task.FromResult(结果);
}
//异步的
公共重写异步任务运行()
{
var result=wait DoSomethingAsync();
返回结果;
}
wait
ing上面第一个示例的结果不会执行任何线程切换或类似操作。wait
ing第二个示例的结果可能会执行,具体取决于DoSomethingAsync()的实现
。没有特别需要抽象层:您可以随时检查任务是否已完成,并且等待等待一个已完成的任务将始终立即返回值。用于返回包含同步计算结果的任务,然后等待
bool ok = DoSomething();
return Task.FromResult(ok);
作为旁注,我不会将同步代码放在一个通常是异步的(或在其他类/位置是同步的)方法中,反之亦然。对于同步和异步实现,我会使用不同的接口/基类
interface IRunnable
{
bool IsRunning;
bool Run();
}
interface IRunnableAsync
{
bool IsRunning;
Task<bool> RunAsync();
}
接口IRunnable
{
布尔正在运行;
bool-Run();
}
接口同步
{
布尔正在运行;
任务RunAsync();
}
然后在UI中,我想等待异步任务(如果用户在运行时配置中指定了异步任务)
首先,我不得不说这是一个非常糟糕的主意。有些东西应该是可配置的,有些不应该。操作的异步性不应该是可配置的。这是一个可怕的设计,我要做的第一件事就是对荒谬的“需求”进行严格的回击就像这样。它与是否抛出异常的可配置标志具有相同的意义
这就是说,这是可以做到的。这很痛苦,很难维持,而且在一天结束时完全没有用。但是,嘿,我想你会为此得到报酬,所以一切都很好,嗯
如果出于政治原因(绝对没有有效的技术原因),您必须执行此操作,那么我建议您使用。仅阻塞(Result
)的一个问题是,如果Run
使用wait
(for),则无法执行此操作
布尔参数hack只是添加一个布尔参数,指示该方法是否需要同步完成
public abstract class Base
{
public abstract Task<bool> RunAsync(bool sync);
}
这叫做:
private async void OnRun(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Base baseCaseRunner = GetCaseRunner(case);
try
{
bool sync = !something_holds;
bool ok = await baseCaseRunner.RunAsync(sync);
}
catch (Exception e)
{
LogError(...);
}
}
}
请注意,它总是可以用await
调用,但是如果sync
为true
,那么OnRun
实际上将是同步的。这是由于“wait fast path”(如我的异步介绍博客文章中所述).你能用高级术语解释一下你想做什么吗?@YacoubMassad:让我试试。我正在尝试创建一个抽象类和一个派生类,它们异步实现一些方法,而另一个派生类则不异步实现,然后在UI中根据我所处的情况有条件地等待。看看这个:WRT edit#2:你是We’我们试图对一个只希望由特定线程访问的对象执行某些操作。这种情况经常发生在具有指定UI线程的应用程序中。如果不知道是哪行代码导致了错误,就很难确切地知道如何帮助您。@StriplingWarrior:我正在尝试进一步调试,但到目前为止,在Ed中的用法是否正确它#1看起来还好吗?谢谢,很高兴知道我可以在任何任务上使用wait。那么我甚至不需要if-condition。但是如果对于您示例中的异步运行方法,我无法像您那样在DoSomethingAsync上使用wait(即,我不想使用async关键字而只返回任务),该怎么办由于我的任务是使用lambda函数定义的。我想我接下来的问题是,如果我需要使用lambda函数来实例化任务,如何使用async/await关键字?我找到了上面问题的答案。请参阅我的编辑1。我将对此进行测试并稍后返回
private async void OnRun(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Base baseCaseRunner = GetCaseRunner(case);
try
{
bool ok = true;
ok = await baseCaseRunner.Run();
}
catch (Exception e)
{
LogError(...);
}
}
}
// synchronous
public override Task<bool> Run()
{
var result = DoSomething();
return Task.FromResult(result);
}
// asynchronous
public override async Task<bool> Run()
{
var result = await DoSomethingAsync();
return result;
}
bool ok = DoSomething();
return Task.FromResult(ok);
interface IRunnable
{
bool IsRunning;
bool Run();
}
interface IRunnableAsync
{
bool IsRunning;
Task<bool> RunAsync();
}
public abstract class Base
{
public abstract Task<bool> RunAsync(bool sync);
}
internal class Derived1 : Base
{
public override async Task<bool> RunAsync(bool sync)
{
IsRunning = true;
try
{
if (sync)
return DoSomething();
return await Task.Run(() => DoSomething());
}
finally
{
IsRunning = false;
}
}
}
private async void OnRun(object sender, EventArgs args)
{
foreach (var case in Cases)
{
Base baseCaseRunner = GetCaseRunner(case);
try
{
bool sync = !something_holds;
bool ok = await baseCaseRunner.RunAsync(sync);
}
catch (Exception e)
{
LogError(...);
}
}
}