You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 10:40:27