C# 注册表 ObjectDisposedException 案例

C# Registry ObjectDisposedException Cases

我正在用 C# 编写一个访问 Windows 注册表的应用程序。

我的高层次问题是:在使用 Registry.LocalMachine.OpenSubKey(key) 时是否有任何情况会导致抛出 ObjectDisposedException?

此代码在我的应用程序中只会 运行 在管理权限下,并且密钥是一个永远不会为 null 的常量。我的第一直觉是这个静态调用永远不会抛出 ObjectDisposedException,因为 MSDN 文档(linked here) 声明它只会在 RegistryKey 关闭时抛出,但我在 MSDN 中找不到是否可以通过静态调用 运行 进入关闭的 RegistryKey。

感谢您的帮助!

测试是这样的:

Registry.LocalMachine.Close();
Registry.LocalMachine.Dispose();
var hardwareKey = Registry.LocalMachine.OpenSubKey("HARDWARE");

Registry.LocalMachinereturns一个RegistryKey。如果您实际上可以关闭 and/or 处理它,那么下一行应该抛出异常,但它不会。

如果您对另一个注册表项执行相同的操作 - 关闭它然后尝试打开一个子项,它将抛出 ObjectDisposedException.

var hardwareKey = Registry.LocalMachine.OpenSubKey("HARDWARE");
hardwareKey.Close();
// throws the exception.
var descriptionKey = hardwareKey.OpenSubKey("DESCRIPTION");

为什么他们的行为不同?

根据 the source codeRegistryKey.Close 调用 Dispose。但是 Registry.LocalMachine 返回的特定 RegistryKey 将永远不会被关闭。

这没有记录(源代码除外)所以是否依赖它取决于您。但是,如果您通过静态方法访问注册表项,那么您不应该 close/dispose 它是有道理的。

如果按照这个逻辑,系统键(包括HKEY_LOCAL_MACHINE)除了HKEY_PERFORMANCE_DATA外不会被处理掉。

[System.Security.SecuritySafeCritical]  // auto-generated
private void Dispose(bool disposing)
{
    if (hkey != null)
    {
        if (!IsSystemKey())
        {
            try
            {
                hkey.Dispose();
            }
            catch (IOException)
            {
                // we don't really care if the handle is invalid at this point
            }
            finally
            {
                hkey = null;
            }
        }
        else if (disposing && IsPerfDataKey())
        {
            // System keys should never be closed.  However, we want to call RegCloseKey
            // on HKEY_PERFORMANCE_DATA when called from PerformanceCounter.CloseSharedResources
            // (i.e. when disposing is true) so that we release the PERFLIB cache and cause it
            // to be refreshed (by re-reading the registry) when accessed subsequently. 
            // This is the only way we can see the just installed perf counter.  
            // NOTE: since HKEY_PERFORMANCE_DATA is process wide, there is inherent ---- in closing
            // the key asynchronously. While Vista is smart enough to rebuild the PERFLIB resources
            // in this situation the down level OSes are not. We have a small window of ---- between  
            // the dispose below and usage elsewhere (other threads). This is By Design. 
            // This is less of an issue when OS > NT5 (i.e Vista & higher), we can close the perfkey  
            // (to release & refresh PERFLIB resources) and the OS will rebuild PERFLIB as necessary. 
            SafeRegistryHandle.RegCloseKey(RegistryKey.HKEY_PERFORMANCE_DATA);
        }
    }
}