等待抽象的异步任务

squ*_*boo 1 c# task abstract async-await

我对这个async/await用法很新.我试图await在UI中抽象异步和条件.我有一个抽象的基类:

public abstract class Base
{
    public abstract bool IsRunning { get; }
    public abstract Task<bool> Run();
}
Run Code Online (Sandbox Code Playgroud)

从它一些派生的实例,第一个是同步的:

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()
    {
        task = new Task<bool>(() => 
        {
            bool ok = DoSomething();
            return ok;
        });
        return task;
    }
}
Run Code Online (Sandbox Code Playgroud)

和异步实现的派生类:

internal class Derived2 : Base
{
    private readonly Base baseCase;
    private Task<bool> task;
    public Derived2(Base baseCase)
    {
        this.baseCase = baseCase;
    }
    public override bool IsRunning
    {
        get { return task != null && task.Status == TaskStatus.Running; }
    }
    public override Task<bool> Run()
    {
        task = new Task<bool>(() => 
        {
            bool ok = DoSomething();
            return ok;
        });
        return task;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在UI中,我想awaitasynchronous任务上(如果用户在运行时配置中指定),如下所示:

internal class CaseMenuHandler
{
    private async void OnRun(object sender, EventArgs args)
    {
        foreach (var case in Cases)
        {
            Base baseCaseRunner = GetCaseRunner(case);
            try
            {
                bool ok = true;
                if( something_holds ) {
                    ok = await baseCaseRunner.Run();
                }
                else {
                    ok = baseCaseRunner.Run().Result;
                }
            }
            catch (Exception e)
            {
                LogError(...);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

希望这很清楚.我可以这样做,特别是在if块内有条件地等待吗?理想情况下,我想使Base类只返回bool,而不是Task<bool>Run方法,而只显示Derived2类重写返回一个Task<bool>,但我不如何做到这一点清楚.也许我应该回归task.Result里面的Run方法Derived2?如果有更好的方法,包括抽象或任何​​其他更正,请告诉我.欣赏任何想法.

编辑#1

在下面的答复中阐明Run了同步实施的方法形式Derived1.我不能改变的签名DoSomething,虽然方法,所以鉴于此,我Run在方法Derived2(异步执行)如下所示现在(感谢@瘦长的评论):

    public override async Task<bool> Run()
    {
        task = new Task<bool>(() => 
        {
            bool ok = DoSomething();
            return ok;
        });
        task.Start();
        return await task;
    }
Run Code Online (Sandbox Code Playgroud)

编辑#2:

当我尝试上面的内容时(也尝试task.Start()task定义后调用,我收到以下错误:

Cross-thread operation not valid: Application accessed domain object from a thread other than a legal thread.
Run Code Online (Sandbox Code Playgroud)

Str*_*ior 6

我可以这样做,特别是在if块内有条件地等待吗?

可以,但你不应该这样做.如果你做得对,那么以阻塞方式专门调用同步任务没有什么大的优势:作为一般规则,你可以只await返回返回的任务,如果它代表一个同步任务,那么await将同步解决这个问题.高架.

当我说"如果你做对了",这是正确的方法:

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

await上面第一个例子的结果不会做任何线程切换或类似的事情.await取决于实施的第二种可能的结果DoSomethingAsync().还有的抽象层没有特别的需要:你总是可以检查Task到是否它完成与否,以及await荷兰国际集团已经完成的任务将总是立即返回一个值.