简体   繁体   English

等效于F#StartImmediate

[英]Equivalent of F# StartImmediate

Is there a C# equivalent of F#'s StartImmediate which can be executed on a Task ? 是否有可以在Task上执行的F#的StartImmediate的C#等效项? I have a situation where I need to await a function sometimes, but other times I just want the method to call back to the UI thread without using await . 我遇到的情况是有时需要等待一个函数,但是有时我只希望该方法不使用await即可回调UI线程。

I want to avoid async void if possible. 我想尽可能避免异步无效。

Example: 例:

public async void DoSomething()
{
    //before runs on UI thread
    await OtherThing();
    //after runs on UI thread
}

public async Task DoSomethingElse()
{
    //before runs on UI thread
    await OtherThing();
    //I want this to run on the UI thread
}

public void CallDoSomething()
{
    DoSomething(); //no need to await, returns to the UI thread to continue execution

    DoSomethingElse();//Doesn't return to the UI thread to continue execution

    DoSomethingElse().???(); // how to return to the UI thread for the async callback?
}

In F# this would look like this: 在F#中,它看起来像这样:

let CallDoSomething () =

    //more code here

    async {
        //runs on the current thread
        do! OtherThing()
        //runs on the current thread
    } |> Async.StartImmediate

    //code here doesn't wait for the async to finish

So, when looking at your code example. 因此,在查看您的代码示例时。 You have an async method that return a Task . 您有一个async方法返回Task You're calling that method, and then calling Start on the resulting task (without calling await ). 您正在调用该方法,然后在生成的任务上调用Start (而不调用await )。 That will throw an exception at runtime. 这将在运行时引发异常。 The task is already started just by calling the method. 仅通过调用该方法即可启动该任务。 Starting an already running task (or a completed task, if it completed before it returned) will throw an exception. 启动已经运行的任务(或完成的任务,如果在返回之前已完成),将引发异常。 You can only Start a task created using the Task constructor, which you're not using. 您只能Start使用的Task构造函数创建的Task

You also claim, in comments, that you are not in the UI thread when you return after calling DoSomethingElse . 您还声称,在调用DoSomethingElse后返回时,您已在注释中声明您不在UI线程中。 That is false. 那是错误的。 The code will run in the UI thread. 该代码在UI线程中运行。

You also imply that the await in DoSomethingElse won't marshal the callback to the UI thread, but it will . 您还暗示DoSomethingElse中的await不会编组UI线程的回调,但是 Since it was called from the UI thread, it captured the UI context, and uses it when calling await . 由于是从UI线程调用的,因此它捕获了UI上下文,并在调用await时使用它。

So in short, you need to do nothing except remove the call to Start . 简而言之,除了删除对Start的调用之外,您无需执行任何其他操作。

The one problem you do have, if you structure your code like this, is that you will never know if your code errors out, as there is nothing to observe any exceptions. 如果您这样构造代码,您确实遇到的一个问题是您将永远不会知道代码是否出错,因为没有什么可以观察到任何异常。 There are two ways you could address this. 有两种解决方法。 One would be for each of the methods you call in this manor to consider themselves "top level methods" and handle all exceptions instead of every throwing any. 一种方法是让您在此庄园中调用的每种方法都将自己视为“顶级方法”,并处理所有异常,而不是每次抛出任何异常。

The other option would be to store all of the tasks called in this manner and await Task.WhenAll those tasks, so you can observe any errors when they all finish. 另一个选择是存储以这种方式调用的所有任务,然后await Task.WhenAll这些任务,这样您就可以在完成所有错误时观察到它们。

您是否尝试过Task类的RunSynchronously()方法?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM