避免使用C#中的Application.DoEvents()

许多优秀的程序员(包括很多优秀的Stackoverflow成员)都反对使用Application.DoEvents()无论情况如何。 实际上它甚至得到了网络上大量文章的支持,比如这篇 关于SO的着名辩论 ……

虽然,我陷入了一个案例,其中(I)认为DoEvents()是独特的退出(缺乏经验)。 这就像介绍一样,让我们​​看一些编码。

我有一个’serialPort’组件通过串行通信连接控制器,发送命令并等待它的响应,就是这样。

 string response = ""; bool respFlag; private string sendCommand(string command) { respFlag = false; //initialize respFlag serialPort1.Write(command); // send the command Stopwatch timer = Stopwatch.StartNew(); // start a timer while(true) { // break from the loop if receive a response if(respFlag) break; // timeOut error if no response for more than 500msec if(timer.ElapsedMilliseconds >= 500) break; // here comes the UGLY part Application.DoEvents(); } return response; } 

在我的serialPort的DataReceived方法中,我读取了现有的响应并打破了循环

 private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { response = serialPort1.ReadExisting(); // set the flag to true to exit the infinite loop in sendCommand respFlag = true; } 

它不完全是这样的,但是这是一个示例代码,显示我是如何通过串行通信接收的,您是否愿意告诉我在哪里迫使自己陷入这个陷阱?

如果您使用的是.NET 4.5,那么使用async / await和TaskCompletionSource以及async / await非常容易。

 TaskCompletionSource resultTcs = new TaskCompletionSource(); private async Task SendCommandAsync(string command) { serialPort1.Write(command); // send the command var timeout = Task.Delay(500); //Wait for either the task to finish or the timeout to happen. var result = await Task.WhenAny(resultTcs.Task, timeout).ConfigureAwait(false); //Was the first task that finished the timeout task. if (result == timeout) { throw new TimeoutException(); //Or whatever you want done on timeout. } else { //This await is "free" because the task is already complete. //We could have done ((Task)result).Result but I //don't like to use .Result in async code even if I know I won't block. return await (Task)result; } } private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { var response = serialPort1.ReadExisting(); tcs.SetResult(response); //reset the task completion source for another call. resultTcs = new TaskCompletionSource(); } 

您应该使用async I / O方法。 异步等待Task 完成超时是一个很好的例子。

我假设答案是在不同的线程中运行该循环,并在响应可用时向UI发送消息。 这假设您出于某种原因无法执行异步IO