我如何以编程方式使用“使用"?C#中的关键字?

问题描述:

我有一些 System.Diagnotics.Processes 需要运行.我想自动调用它们的 close 方法.显然,使用"关键字对我来说是这样做的.

I have some System.Diagnotics.Processes to run. I'd like to call the close method on them automatically. Apparently the "using" keyword does this for me.

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

Is this the way to use the using keyword?

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
    }
}

我想启动多个进程以同时运行.

I'd like to start multiple processes to run concurrently.

using(p = Process.Start(command))

这将编译,因为 Process 类实现了 IDisposable,但是您实际上想要调用 Close 方法.
从逻辑上讲,Dispose 方法会为您调用 Close,通过使用反射器深入研究 CLR,我们可以看到它实际上为我们执行了此操作.到目前为止一切顺利.

This will compile, as the Process class implements IDisposable, however you actually want to call the Close method.
Logic would have it that the Dispose method would call Close for you, and by digging into the CLR using reflector, we can see that it does in fact do this for us. So far so good.

再次使用反射器,我查看了 Close 方法的作用 - 它释放了底层的原生 win32 进程句柄,并清除了一些成员变量.这(释放外部资源)正是 IDisposable 模式应该做的.

Again using reflector, I looked at what the Close method does - it releases the underlying native win32 process handle, and clears some member variables. This (releasing external resources) is exactly what the IDisposable pattern is supposed to do.

但是我不确定这是否是您想要在这里实现的目标.

However I'm not sure if this is what you want to achieve here.

释放底层句柄只是对 windows 说我不再对跟踪这个其他进程感兴趣".它实际上不会导致其他进程退出,或导致您的进程等待.

Releasing the underlying handles simply says to windows 'I am no longer interested in tracking this other process'. At no point does it actually cause the other process to quit, or cause your process to wait.

如果你想强制他们退出,你需要在进程上使用 p.Kill() 方法 - 但是请注意,杀死进程永远不是一个好主意,因为它们可以自己不清理,可能会留下损坏的文件等.

If you want to force them quit, you'll need to use the p.Kill() method on the processes - however be advised it is never a good idea to kill processes as they can't clean up after themselves, and may leave behind corrupt files, and so on.

如果您想等待它们自行退出,您可以使用 p.WaitForExit() - 但是这仅在您一次等待一个进程时有效.如果你想同时等待它们,那就很棘手了.

If you want to wait for them to quit on their own, you could use p.WaitForExit() - however this will only work if you're waiting for one process at a time. If you want to wait for them all concurrently, it gets tricky.

通常您会为此使用 WaitHandle.WaitAll,但因为无法从 System.Diagnostics.ProcessWaitHandle 对象/code>,你不能这样做(说真的,微软在想什么?)

Normally you'd use WaitHandle.WaitAll for this, but as there's no way to get a WaitHandle object out of a System.Diagnostics.Process, you can't do this (seriously, wtf were microsoft thinking?).

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

You could spin up a thread for each process, and call `WaitForExit in those threads, but this is also the wrong way to do it.

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

You instead have to use p/invoke to access the native win32 WaitForMultipleObjects function.

这是一个示例(我已经测试过,并且确实有效)

Here's a sample (which I've tested, and actually works)

[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

}