문제

Is there a C# equivalent of F#'s StartImmediate which can be executed on a Task? 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.

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:

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. You're calling that method, and then calling Start on the resulting task (without calling 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.

You also claim, in comments, that you are not in the UI thread when you return after calling DoSomethingElse. That is false. The code will run in the UI thread.

You also imply that the await in DoSomethingElse won't marshal the callback to the UI thread, but it will. Since it was called from the UI thread, it captured the UI context, and uses it when calling await.

So in short, you need to do nothing except remove the call to 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.

다른 팁

Did you try the RunSynchronously() method of the Task class ?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top