C#中各类需应用Dispose模式的非托管资源实用示例咨询
Dispose模式对应各类非托管资源的C#实用示例
.NET文档指出,当与以下非托管资源交互时,应使用Dispose模式:
- 文件句柄(file handles)
- 管道句柄(pipe handles)
- 注册表句柄(registry handles)
- 等待句柄(wait handles)
- 指向非托管内存块的指针
以下是每类资源对应的实用C#示例:
1. 文件句柄
示例1:使用内置IDisposable类型(推荐)
using (var fileStream = new FileStream("example.txt", FileMode.Open)) { byte[] buffer = new byte[1024]; fileStream.Read(buffer, 0, buffer.Length); // 执行文件读写操作 }
示例2:手动封装非托管文件句柄(演示Dispose模式)
public class CustomFileHandler : IDisposable { private IntPtr _fileHandle; private bool _disposed = false; public CustomFileHandler(string filePath) { _fileHandle = NativeMethods.CreateFile(filePath, NativeMethods.GENERIC_READ, 0, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero); if (_fileHandle == NativeMethods.INVALID_HANDLE_VALUE) { throw new IOException("打开文件失败"); } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_disposed) return; if (_fileHandle != NativeMethods.INVALID_HANDLE_VALUE) { NativeMethods.CloseHandle(_fileHandle); _fileHandle = NativeMethods.INVALID_HANDLE_VALUE; } _disposed = true; } ~CustomFileHandler() => Dispose(false); private static class NativeMethods { public const uint GENERIC_READ = 0x80000000; public const uint OPEN_EXISTING = 3; public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CloseHandle(IntPtr hObject); } }
2. 管道句柄
示例1:内置管道类型(自动Dispose)
using (var pipeServer = new NamedPipeServerStream("MyPipe", PipeDirection.InOut)) { pipeServer.WaitForConnection(); byte[] buffer = new byte[256]; pipeServer.Read(buffer, 0, buffer.Length); // 执行管道读写操作 }
示例2:手动封装非托管管道句柄
public class CustomPipeHandler : IDisposable { private IntPtr _pipeHandle; private bool _disposed = false; public CustomPipeHandler(string pipeName) { string pipePath = $"\\\\.\\pipe\\{pipeName}"; _pipeHandle = NativeMethods.CreateNamedPipe(pipePath, NativeMethods.PIPE_ACCESS_DUPLEX, NativeMethods.PIPE_TYPE_BYTE | NativeMethods.PIPE_WAIT, 1, 1024, 1024, 0, IntPtr.Zero); if (_pipeHandle == NativeMethods.INVALID_HANDLE_VALUE) { throw new IOException("创建管道失败"); } } public void WaitForConnection() { if (!NativeMethods.ConnectNamedPipe(_pipeHandle, IntPtr.Zero)) { throw new IOException("连接管道失败"); } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_disposed) return; if (_pipeHandle != NativeMethods.INVALID_HANDLE_VALUE) { NativeMethods.DisconnectNamedPipe(_pipeHandle); NativeMethods.CloseHandle(_pipeHandle); _pipeHandle = NativeMethods.INVALID_HANDLE_VALUE; } _disposed = true; } ~CustomPipeHandler() => Dispose(false); private static class NativeMethods { public const uint PIPE_ACCESS_DUPLEX = 0x00000003; public const uint PIPE_TYPE_BYTE = 0x00000000; public const uint PIPE_WAIT = 0x00000000; public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern IntPtr CreateNamedPipe(string lpName, uint dwOpenMode, uint dwPipeMode, uint nMaxInstances, uint nOutBufferSize, uint nInBufferSize, uint nDefaultTimeOut, IntPtr lpSecurityAttributes); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool ConnectNamedPipe(IntPtr hNamedPipe, IntPtr lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DisconnectNamedPipe(IntPtr hNamedPipe); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CloseHandle(IntPtr hObject); } }
3. 注册表句柄
示例1:内置RegistryKey类型
using (var registryKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows")) { if (registryKey != null) { object value = registryKey.GetValue("SomeValue"); // 处理注册表值 } }
示例2:手动封装非托管注册表句柄
public class CustomRegistryHandler : IDisposable { private IntPtr _registryHandle; private bool _disposed = false; public CustomRegistryHandler(string subKeyPath) { int result = NativeMethods.RegOpenKeyEx(IntPtr.Zero, subKeyPath, 0, NativeMethods.KEY_READ, out IntPtr hKey); if (result != 0) { throw new Win32Exception(result); } _registryHandle = hKey; } public string GetValue(string valueName) { const int bufferSize = 1024; StringBuilder buffer = new StringBuilder(bufferSize); uint bufferLength = (uint)bufferSize; uint type = 0; int result = NativeMethods.RegQueryValueEx(_registryHandle, valueName, IntPtr.Zero, ref type, buffer, ref bufferLength); if (result != 0) { throw new Win32Exception(result); } return buffer.ToString(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_disposed) return; if (_registryHandle != IntPtr.Zero) { NativeMethods.RegCloseKey(_registryHandle); _registryHandle = IntPtr.Zero; } _disposed = true; } ~CustomRegistryHandler() => Dispose(false); private static class NativeMethods { public const uint KEY_READ = 0x20019; [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern int RegOpenKeyEx(IntPtr hKey, string lpSubKey, uint ulOptions, uint samDesired, out IntPtr phkResult); [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern int RegQueryValueEx(IntPtr hKey, string lpValueName, IntPtr lpReserved, ref uint lpType, StringBuilder lpData, ref uint lpcbData); [DllImport("advapi32.dll", SetLastError = true)] public static extern int RegCloseKey(IntPtr hKey); } }
4. 等待句柄
示例1:内置等待句柄类型
using (var resetEvent = new ManualResetEvent(false)) { ThreadPool.QueueUserWorkItem(state => { Thread.Sleep(2000); resetEvent.Set(); }); resetEvent.WaitOne(); // 事件触发后执行操作 }
示例2:手动封装非托管等待句柄
public class CustomWaitHandle : IDisposable { private IntPtr _waitHandle; private bool _disposed = false; public CustomWaitHandle(bool initialState) { _waitHandle = NativeMethods.CreateEvent(IntPtr.Zero, true, initialState, null); if (_waitHandle == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } public void Set() { if (!NativeMethods.SetEvent(_waitHandle)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } public bool WaitOne(int millisecondsTimeout) { uint result = NativeMethods.WaitForSingleObject(_waitHandle, (uint)millisecondsTimeout); return result == 0; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_disposed) return; if (_waitHandle != IntPtr.Zero) { NativeMethods.CloseHandle(_waitHandle); _waitHandle = IntPtr.Zero; } _disposed = true; } ~CustomWaitHandle() => Dispose(false); private static class NativeMethods { [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetEvent(IntPtr hEvent); [DllImport("kernel32.dll", SetLastError = true)] public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CloseHandle(IntPtr hObject); } }
5. 指向非托管内存块的指针
示例1:使用Marshal类操作非托管内存
public void MarshalMemoryExample() { IntPtr unmanagedPtr = IntPtr.Zero; try { unmanagedPtr = Marshal.AllocHGlobal(1024); string data = "Hello Unmanaged"; Marshal.StringToHGlobalUni(data, unmanagedPtr); string retrievedData = Marshal.PtrToStringUni(unmanagedPtr); // 处理读取到的数据 } finally { if (unmanagedPtr != IntPtr.Zero) { Marshal.FreeHGlobal(unmanagedPtr); } } }
示例2:封装非托管内存的Dispose模式实现
public class UnmanagedMemoryBuffer : IDisposable { private IntPtr _bufferPtr; private int _bufferSize; private bool _disposed = false; public UnmanagedMemoryBuffer(int size) { _bufferSize = size; _bufferPtr = Marshal.AllocHGlobal(size); if (_bufferPtr == IntPtr.Zero) { throw new OutOfMemoryException("分配非托管内存失败"); } } public void Write(byte[] data, int offset, int count) { if (count > _bufferSize) { throw new ArgumentOutOfRangeException(nameof(count), "数据超出缓冲区大小"); } Marshal.Copy(data, offset, _bufferPtr, count); } public byte[] Read(int count) { if (count > _bufferSize) { throw new ArgumentOutOfRangeException(nameof(count), "请求长度超出缓冲区大小"); } byte[] data = new byte[count]; Marshal.Copy(_bufferPtr, data, 0, count); return data; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_disposed) return; if (_bufferPtr != IntPtr.Zero) { Marshal.FreeHGlobal(_bufferPtr); _bufferPtr = IntPtr.Zero; } _disposed = true; } ~UnmanagedMemoryBuffer() => Dispose(false); } // 使用示例 using (var buffer = new UnmanagedMemoryBuffer(1024)) { byte[] data = Encoding.UTF8.GetBytes("Test unmanaged buffer"); buffer.Write(data, 0, data.Length); byte[] retrieved = buffer.Read(data.Length); }
内容的提问来源于stack exchange,提问作者Patrik Mihalčin
相关产品推荐
相关产品推荐

