如何以编程方式在C#中使用“using”关键字?

我有一些System.Diagnotics.Processes来运行。 我想自动调用close方法。 显然,“using”关键字为我做了这个。

这是使用using关键字的方式吗?

foreach(string command in S) // command is something like "c:\a.exe" { try { using(p = Process.Start(command)) { // I literally put nothing in here. } } catch (Exception e) { // notify of process failure } } 

我想开始多个进程同时运行。

 using(p = Process.Start(command)) 

这将编译,因为Process类实现了IDisposable ,但是你实际上想要调用Close方法。
逻辑会让Dispose方法为你调用Close ,并且通过使用reflection器挖掘CLR,我们可以看到它确实为我们做了这个。 到现在为止还挺好。

再次使用reflection器,我查看了Close方法的作用 – 它释放了底层的本机win32进程句柄,并清除了一些成员变量。 这(释放外部资源) 正是 IDisposable模式应该做的事情。

但是我不确定这是否是你想要在这里实现的。

释放底层句柄只是对Windows说’我不再对跟踪这个其他过程感兴趣了’。 它决不会导致其他进程退出,或导致进程等待。

如果你想强制它们退出,你需要在进程上使用p.Kill()方法 – 但是请注意,杀死进程永远不是一个好主意,因为它们无法自行清理,并且可能会离开在腐败文件后面,等等。

如果你想等待它们自己退出,你可以使用p.WaitForExit() – 但是这只有在你一次等待一个进程时才有效。 如果你想同时等待它们,那就太棘手了。

通常你会使用WaitHandle.WaitAll ,但由于无法从System.Diagnostics.Process获取WaitHandle对象,所以你不能这样做(严重来说,wtf是微软思考的吗?)。

你可以为每个进程启动一个线程,并在那些线程中调用`WaitForExit,但这也是错误的方法。

您必须使用p / invoke来访问本机win32 WaitForMultipleObjects函数。

这是一个样本(我已经测试过,实际上有效)

 [System.Runtime.InteropServices.DllImport( "kernel32.dll" )] static extern uint WaitForMultipleObjects( uint nCount, IntPtr[] lpHandles, bool bWaitAll, uint dwMilliseconds ); static void Main( string[] args ) { var procs = new Process[] { Process.Start( @"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 2'" ), Process.Start( @"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 3'" ), Process.Start( @"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 4'" ) }; // all started asynchronously in the background var handles = procs.Select( p => p.Handle ).ToArray(); WaitForMultipleObjects( (uint)handles.Length, handles, true, uint.MaxValue ); // uint.maxvalue waits forever } 

供参考: IDisposable对象的using关键字:

 using(Writer writer = new Writer()) { writer.Write("Hello"); } 

只是编译器语法。 它归结为:

 Writer writer = null; try { writer = new Writer(); writer.Write("Hello"); } finally { if( writer != null) { ((IDisposable)writer).Dispose(); } } 

using有点好,因为编译器阻止您在using块中重新分配writer引用。

框架指南第9.3.1节。 256状态:

除了Dispose()之外, CONSIDER提供方法Close(),如果close是该区域中的标准术语。


在您的代码示例中,不需要外部try-catch(参见上文)。

使用可能不是你想要的,因为一旦p超出范围就会调用Dispose()。 这不会关闭进程(已测试)。

进程是独立的,所以除非你调用p.WaitForExit() ,否则它们会脱离并完全独立于你的程序而做自己的事情。

与直觉相反,对于Process,Close()仅释放资源但使程序保持运行。 CloseMainWindow()可以用于某些进程,Kill()可以杀死任何进程。 CloseMainWindow()和Kill()都可以抛出exception,所以如果你在finally块中使用它们要小心。

要完成,这里有一些代码等待进程完成但不会在发生exception时终止进程。 我不是说它比猎户座爱德华兹更好,只是不同。

 List processList = new List(); try { foreach (string command in Commands) { processList.Add(System.Diagnostics.Process.Start(command)); } // loop until all spawned processes Exit normally. while (processList.Any()) { System.Threading.Thread.Sleep(1000); // wait and see. List finished = (from o in processList where o.HasExited select o).ToList(); processList = processList.Except(finished).ToList(); foreach (var p in finished) { // could inspect exit code and exit time. // note many properties are unavailable after process exits p.Close(); } } } catch (Exception ex) { // log the exception throw; } finally { foreach (var p in processList) { if (p != null) { //if (!p.HasExited) // processes will still be running // but CloseMainWindow() or Kill() can throw exceptions p.Dispose(); } } } 

我没有打扰Kill()关闭进程,因为代码开始变得更加丑陋。 有关更多信息,请阅读msdn文档。

 try { foreach(string command in S) // command is something like "c:\a.exe" { using(p = Process.Start(command)) { // I literally put nothing in here. } } } catch (Exception e) { // notify of process failure } 

它起作用的原因是因为当exception发生时,变量p超出范围,因此调用Dispose方法来关闭进程就是这样。 另外,我认为你想要为每个命令关闭一个线程,而不是等到一个可执行文件完成后才能进入下一个命令。