应该为 Process.GetCurrentProcess() 调用 Dispose 吗?
Should one call Dispose for Process.GetCurrentProcess()?
例如,参见
How to get the current ProcessID?
没有人愿意为 System.Diagnostics.Process.GetCurrentProcess()
返回的对象调用 Dispose。它真的应该被调用吗?请解释原因。
是的,其实也很重要。如果你看到实际的 source,你会看到 Dispose
不仅继承自 Component
,它也做了一些事情。
在我看来,查看该代码时,将 EnableRaisingEvents
设置为 true
时最为重要,因为这涉及创建等待句柄。需要释放该句柄以防止内存和句柄泄漏。
这是一个艰难的决定。
您可能不必为从 Process.GetCurrentProcess()
获得的 Process
实例调用 Dispose
,以防您没有触及 Handle
属性以及其他一些敏感点。
让我们看看包含Dispose
逻辑本质的Process.Close
方法。
public void Close()
{
if (this.Associated)
{
if (this.haveProcessHandle)
{
this.StopWatchingForExit();
this.m_processHandle.Close();
this.m_processHandle = null;
this.haveProcessHandle = false;
}
this.haveProcessId = false;
this.isRemoteMachine = false;
this.machineName = ".";
this.raisedOnExited = false;
this.standardOutput = null;
this.standardInput = null;
this.standardError = null;
this.Refresh();
}
}
您可以看到,只有当 Process
实例具有进程句柄时,这里才会发生一些真实的事情。 Refresh
方法与我们的主题无关。
如果进一步观察,您会发现当 Handle
属性 被访问时,进程句柄可以被 Process
实例获取(并因此持有)。不过这不是唯一的案例!
public IntPtr Handle
{
get
{
this.EnsureState(Process.State.Associated);
return this.OpenProcessHandle().DangerousGetHandle();
}
}
作为一般规则:如果它实现了 IDisposable
- 你应该调用 Dispose
.
在您的特定情况下,如果您只触摸当前进程名称或无辜的东西,您可以省略 Dispose
调用并摆脱它。
这是一个例子:
Process process = Process.GetCurrentProcess();
var fieldInfo = typeof(Process).GetField("haveProcessHandle", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var v1 = fieldInfo.GetValue(process);
//v1 is false. Explicit Dispose is not necessary.
var processName = process.ProcessName;
var v2 = fieldInfo.GetValue(process);
//v2 is false. Explicit Dispose is not necessary.
var processHandle = process.Handle;
var v3 = fieldInfo.GetValue(process);
//v3 is true. Bah. Explicit Dispose IS necessary from now on.
我使用反射的唯一原因是:如果您通过 Visual Studio 调试器监视 process
变量,它将遍历属性并读取可怕的 Handle
属性.
Process
class 是“糟糕的设计模式”的完美示例,因为它在 get 访问器中彻底改变了对象状态。
例如,参见
How to get the current ProcessID?
没有人愿意为 System.Diagnostics.Process.GetCurrentProcess()
返回的对象调用 Dispose。它真的应该被调用吗?请解释原因。
是的,其实也很重要。如果你看到实际的 source,你会看到 Dispose
不仅继承自 Component
,它也做了一些事情。
在我看来,查看该代码时,将 EnableRaisingEvents
设置为 true
时最为重要,因为这涉及创建等待句柄。需要释放该句柄以防止内存和句柄泄漏。
这是一个艰难的决定。
您可能不必为从 Process.GetCurrentProcess()
获得的 Process
实例调用 Dispose
,以防您没有触及 Handle
属性以及其他一些敏感点。
让我们看看包含Dispose
逻辑本质的Process.Close
方法。
public void Close()
{
if (this.Associated)
{
if (this.haveProcessHandle)
{
this.StopWatchingForExit();
this.m_processHandle.Close();
this.m_processHandle = null;
this.haveProcessHandle = false;
}
this.haveProcessId = false;
this.isRemoteMachine = false;
this.machineName = ".";
this.raisedOnExited = false;
this.standardOutput = null;
this.standardInput = null;
this.standardError = null;
this.Refresh();
}
}
您可以看到,只有当 Process
实例具有进程句柄时,这里才会发生一些真实的事情。 Refresh
方法与我们的主题无关。
如果进一步观察,您会发现当 Handle
属性 被访问时,进程句柄可以被 Process
实例获取(并因此持有)。不过这不是唯一的案例!
public IntPtr Handle
{
get
{
this.EnsureState(Process.State.Associated);
return this.OpenProcessHandle().DangerousGetHandle();
}
}
作为一般规则:如果它实现了 IDisposable
- 你应该调用 Dispose
.
在您的特定情况下,如果您只触摸当前进程名称或无辜的东西,您可以省略 Dispose
调用并摆脱它。
这是一个例子:
Process process = Process.GetCurrentProcess();
var fieldInfo = typeof(Process).GetField("haveProcessHandle", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var v1 = fieldInfo.GetValue(process);
//v1 is false. Explicit Dispose is not necessary.
var processName = process.ProcessName;
var v2 = fieldInfo.GetValue(process);
//v2 is false. Explicit Dispose is not necessary.
var processHandle = process.Handle;
var v3 = fieldInfo.GetValue(process);
//v3 is true. Bah. Explicit Dispose IS necessary from now on.
我使用反射的唯一原因是:如果您通过 Visual Studio 调试器监视 process
变量,它将遍历属性并读取可怕的 Handle
属性.
Process
class 是“糟糕的设计模式”的完美示例,因为它在 get 访问器中彻底改变了对象状态。