C#类中执行进程的异步方法我对这篇文章有一个后续问题。在我的版本中,我有以下我想要异步的。这是我的:publicvirtualTaskExecuteAsync(){vartcs=newTaskCompletionSource();字符串exe=Spec.GetExecutablePath();stringargs=string.Format("--input1={0}--input2={1}",Input1,Input2);try{varprocess=newProcess{EnableRaisingEvents=true,StartInfo={UseShellExecute=false,FileName=exe,Arguments=args,RedirectStandardOutput=true,RedirectStandardError=true,WorkingDir=CaseDir}};process.Exited+=(sender,arguments)=>{if(process.ExitCode!=0){stringerrorMessage=process.StandardError.ReadToEndAsync();tcs.SetResult(假);tcs.SetException(newInvalidOperationException("进程没有正确退出。错误信息:"+errorMessage));}else{File.WriteAllText(LogFile,process.StandardOutput.ReadToEnd());tcs.SetResult(真);}处理.Dispose();};过程。开始();}catch(Exceptione){Logger.InfoOutputWindow(e.Message);tcs.SetResult(假);返回tcs.Task;}返回tcs.Task;}}这里的Spec、Input1、Input2、CaseDir、LogFile都是一个以ExecuteAsync为方法的类的成员,可以这样用吗?我正在努力解决的部分是:我似乎无法在方法定义中使用async关键字(publicvirtualasyncTaskExecuteAsync())而不警告我需要await关键字,而我在lambda表达式中有一个过程。我什至需要在方法定义中使用async关键字吗?我见过他们不使用它的所谓的异步示例,例如这个。如果我把它拿出来编译,但是我可以异步使用它吗?我是否在lambda表达式中使用了async关键字,相应的awaitprocess.StandardError.ReadToEndAsync()在进程lambda表达式中是否正常?在这个例子中,他们并没有在相应的行上使用asyncawait,所以我想知道他们是如何逃脱的?它不会让它阻塞,因为我被告知ReadToEnd方法正在阻塞吗?我调用File.WriteAllText(LogFile,process.StandardOutput.ReadToEnd())会导致整个方法阻塞吗?如果是这样,如果可能的话,我怎样才能避免这种情况?异常处理有意义吗?是否有我应该在catch块中使用的应用程序记录器方法Logger.InfoOutputWindow的任何详细信息?最后,为什么在我遇到的所有示例中,process.Exited事件总是出现在process.Start()之前?我可以将process.Start()放在process.Exited事件之前吗?感谢您的任何想法,并提前感谢您的兴趣和关注。编辑#1:对于上面的#3,我有一个想法,部分基于@File.WriteAllText(...)的评论,所以我做了一个更改,将File.WriteAllText(...)调用移动到文件。process.ExitedFile.WriteAllText(...)事件在WriteAllText(...)的else{}块内。也许这解决了#3。编辑#2:我制作了原始更改列表(代码片段现在已更改),基本上删除了函数定义中的async关键字和基于process.Exited事件处理程序中的@RenéVogt的原始注释。尚未尝试以下最新更改。当我跑的时候,我得到了一个例子:一个插件触发了错误:System.InvalidOperationException;尝试在任务已经完成时将其转换为最终状态。应用程序日志工具有如下调整用堆垛:未处理的异常:异常类型:CLR异常(v4)异常详细信息:无消息(未捕获.net异常对象)异常处理程序:未处理的异常过滤器异常线程:未命名线程(id29560)报告编号:0报告ID:{d80f5824-ab11-4626-930a-7bb57ab22a87}本机堆栈:KERNELBASE.dll+0x1A06DRaiseException+0x3Dclr.dll+0x155294clr.dll+0x15508E(0x000007FE99B92E24)(0x00008000B001)(0x00008000B001)Tasks.TaskCompletionSource`1.SetException(异常异常)在..c__DisplayClass3.b__2(对象发送者,EventArgs参数)在System.Diagnostics.Process.RaiseOnExited()在System.Threading.ExecutionContext.RunInternal(ExecutionContextexecutionContext,ContextCallback回调,对象状态,布尔值preserveSyncCtx)atSystem.Threading.ExecutionContext.Run(ExecutionContextexecutionContext,ContextCallbackcallback,Objectstate,BooleanpreserveSyncCtx)atSystem.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(Objectstate,BooleantimedOut)你不需要在方法签名上异步,因为你不需要t使用await这足以返回一个Task。调用者可能等待任务-或者不等待,它与您的方法无关。不要在那个lambda上使用async关键字,也不要在那个lambda上使用asyncReadToEnd。很难预测如果您在事件处理程序实际完成之前从该事件处理程序返回会发生什么。无论如何你都想完成那个方法。它在进程退出时调用,无需使其异步。这与(2)中的相同。我认为可以在此事件处理程序中“同步”执行此操作。它只阻塞处理程序,但在进程退出后调用处理程序,所以我想你没问题。您的异常处理看起来不错,但我会在Exited事件处理程序中添加另一个try/catch块。但这不是基于知识,而是基于经验,到处都可能出错:)为了获得标准和错误输出的更好方法,我建议订阅ErrorDataReceived和OutputDataReceived事件并使用接收到的数据填充StringBuilder。在您的方法中,声明两个StringBuilder:StringBuilderoutputBuilder=newStringBuilder();StringBuildererrorBuilder=newStringBuilder();并在流程实例化后立即订阅事件:process.OutputDataReceived+=(sender,e)=>outputBuilder.AppendLine(e.Data);process.ErrorDataReceived+=(sender,e)=>errorBuilder.AppendLine(e.Data);然后你只需要在调用process.Start()之后立即调用这两个方法(之前它不起作用,因为stdout和stderr还没有打开):process.Start();process.BeginErrorReadLine();process.BeginOutputReadLine();在Exited事件处理程序中,您可以调用outputBuilder.ToString()(或errorBuilder.ToString())而不是ReadToEnd,一切都应该正常工作。不幸的是,还有另一个缺点:如果进程非常快,则可以在Begin*ReadLine调用之前调用Exited处理程序。不知道如何处理这种情况,但这不太可能发生。以上就是C#学习教程的全部内容:执行进程的C#类中的异步方法。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场,如涉及侵权,请点击右边联系管理员删除。如需转载请注明出处:
