C#完全运行异步方法与EndInvoke会不Application.DoEvents

问题描述:

我遇到了一个问题,下面的代码:C#完全运行异步方法与EndInvoke会不Application.DoEvents

private int check = 1; 

private async System.Threading.Tasks.Task AsyncMethod() 
{ 
    check = 2; 
    await ...; 
    check = 3; 
} 

private void Load(object sender, EventArgs e) 
{ 
    var invoke = this.BeginInvoke(async x => 
    { 
     await AsyncMethod(); 
    }); 
    Debug.WriteLine("1: " + check); 
    EndInvoke(invoke); 
    Debug.WriteLine("2: " + check); 
    Application.DoEvents(); 
    Debug.WriteLine("3: " + check); 
} 

我想立即结束AsyncMethod和完全每当我跑EndInvoke。但是,它返回:

1: 1 
2: 2 
3: 3 

而我期望它返回2: 3。有没有办法做到这一点没有Application.DoEvents(因为我想尽可能避免使用)?

编辑:经过进一步测试,似乎Application.DoEvents在这种情况下效果最好。它甚至在AsyncMethod包含多个await调用时有效;所有这些都在EndInvoke之后运行Application.DoEvents时运行。

+1

Brr中,我们编织什么靠不住的网。 BeginInvoke在UI线程上运行它的目标,但它是从已经在UI线程上运行的代码调用的。所以直到代码显式退回到调度程序循环才能执行。因此,只有在调用EndInvoke之前,才能启动*。如果您期望完成异步方法,那么它就不再是异步了,并且没有必要编写这样的代码。 –

+0

我甚至想要使用EndInvoke的原因是因为许多数据正在使用几种方法上的BeginInvoke调用进行加载,并且生成的IAsyncResults被存储。然后对于一些操作,我必须结束使用BeginInvoke开始的所有方法,我在所有IAsyncResults上使用EndInvoke。这很有效(即它完全运行代码),除非该方法有一个等待呼叫,这在某些场合是必需的。因此,我希望它能够在这些情况下工作。 – Marijn

+0

异步代码对于防止UI冻结很有用。这样做会让情况变得更糟。 –

你在找什么是取消,取消只能在.NET中合作完成。

Here is a article来自Microsoft的文档,它解释了使您的任务/线程可取消的过程。但短版本是您需要传递给函数a CancellationToken并在整个方法中检查以取消代码。

private int check = 1; 

private async Task AsyncMethod(CancellationToken token) 
{ 
    check = 2; 
    await Task.Delay(5000, token); //Wait for 5 seconds or till the token is signaled. 
    token.ThrowIfCancellationRequested(); 
    check = 3; 
} 

//Event handlers like this is the only place you are allowed to do async void 
private async void Load(object sender, EventArgs e) 
{ 
    Debug.WriteLine("1: " + check); 
    try 
    { 
     var cts = new CancellationTokenSource(); 
     var task = AsyncMethod(cts.Token); //Start the task 
     cts.Cancel(); 
     await task; //Wait for the task to finish or throw a OperationCanceledException 
     Debug.WriteLine("2: " + check); 
    } 
    catch(OperationCanceledException) 
    { 
     //Do nothing 
    } 
    Debug.WriteLine("3: " + check); 
} 

上面会输出

1: 1 
3: 2 
+0

此代码不会使用'BeginInvoke'运行'AsyncMethod',在我的程序中就是这种情况。 – Marijn

+0

是的,但它确实调用了AsyncMethod而不立即等待它,如果你在UI线程上并且AsnycMethod表现良好,那么它会有相当类似的行为。 –