我如何以编程方式使用“;使用“;关键字
本文关键字:使用 关键字 方式使 编程 | 更新日期: 2023-09-27 17:47:49
我有一些System.Diagnotics.Processes要运行。我想自动调用它们的close方法。显然,"使用"关键字为我做到了这一点。
这是使用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
,通过使用反射器深入研究CLR,我们可以看到它实际上为我们做到了这一点。到目前为止,一切都很好。
再次使用reflector,我研究了Close
方法的作用——它释放了底层的本地win32进程句柄,并清除了一些成员变量。这(释放外部资源)正是IDisposable模式应该做的事情
但是我不确定这是否是您想要实现的目标。
释放底层句柄只是对windows说"我不再对跟踪其他进程感兴趣"。在任何情况下,它都不会导致其他进程退出,或者导致您的进程等待。
如果你想强迫它们退出,你需要在进程上使用p.Kill()
方法-但请注意,杀死进程从来都不是一个好主意,因为它们无法自行清理,可能会留下损坏的文件,等等
如果你想等待他们自己退出,你可以使用p.WaitForExit()
——但只有当你一次等待一个进程时,这才有效。如果你想同时等待它们,这会变得很棘手。
通常情况下,你会使用WaitHandle.WaitAll
,但由于没有办法从System.Diagnostics.Process
中获得WaitHandle
对象,你不能这样做(说真的,微软在想什么?)。
您可以为每个进程启动一个线程,并在这些线程中调用`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(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块内重新分配写入程序引用。
框架指南第9.3.1节第256页规定:
如果Close是该领域的标准术语,则考虑除了Dispose()之外,还提供方法Close()。
在您的代码示例中,外部try-catch是不必要的(请参见上文)。
由于一旦p
超出作用域,就会调用Dispose(),因此在这里使用可能并不是您想要的。这不会关闭进程(已测试)。
进程是独立的,所以除非你调用p.WaitForExit()
,否则它们会完全独立于你的程序而产生并做自己的事情。
与直觉相反,对于进程,Close()只释放资源,但让程序运行。CloseMainWindow()可以用于某些进程,Kill()可以终止任何进程。CloseMainWindow()和Kill()都可以抛出异常,所以如果在finally块中使用它们,请小心。
最后,这里有一些代码等待进程完成,但在发生异常时不会终止进程。我并不是说它比Orion Edwards更好,只是不同而已。
List<System.Diagnostics.Process> processList = new List<System.Diagnostics.Process>();
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<System.Diagnostics.Process> 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
}
它之所以有效,是因为当异常发生时,变量p超出了范围,因此调用了它的Dispose方法来关闭进程。此外,我认为您应该为每个命令旋转一个线程,而不是等待可执行文件完成后再执行下一个命令。