在类型使用者忘记调用 Dispose 的情况下,Dispose 方法,则垃圾回收器将自动调用安全句柄的终结器。

 

Microsoft.Win32.SafeHandles 命名空间中的以下派生类提供安全句柄:

 

  • SafePipeHandle 类。
  • SafeMemoryMappedViewHandle 类。
  • SafeNCryptSecretHandle 类。
  • SafeRegistryHandle 类。
  • SafeWaitHandle 类。

 

Dispose() 

此外,任何非密封类都应具有要实现的附加 Dispose(bool) 重载方法

因此,它具有标准实现:

public void Dispose()
{
   // Dispose of unmanaged resources.
   Dispose(true);
   // Suppress finalization.
   GC.SuppressFinalize(this);
}

Dispose 方法(其值为 true)还是来自终结器(其值为 false)。

方法的主体包含两个代码块:

  • 无论 disposing 参数的值如何,都会执行此块。

  • 它释放的托管资源可包括:

    • SafeHandle.Dispose() 实现。

    • 相比以非确定性方式回收它们,这样做释放的速度更快。

这一点很重要,因为垃圾回收器在终止期间销毁托管对象的顺序是不确定的。

 

使用安全句柄实现释放模式

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

public class DisposableStreamResource : IDisposable
{
    // Define constants.
    protected const uint GENERIC_READ = 0x80000000;
    protected const uint FILE_SHARE_READ = 0x00000001;
    protected const uint OPEN_EXISTING = 3;
    protected const uint FILE_ATTRIBUTE_NORMAL = 0x80;
    private const int INVALID_FILE_SIZE = unchecked((int)0xFFFFFFFF);

    // Define Windows APIs.
    [DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode)]
    protected static extern SafeFileHandle CreateFile(
        string lpFileName, uint dwDesiredAccess,
        uint dwShareMode, IntPtr lpSecurityAttributes,
        uint dwCreationDisposition, uint dwFlagsAndAttributes,
        IntPtr hTemplateFile);

    [DllImport("kernel32.dll")]
    private static extern int GetFileSize(
        SafeFileHandle hFile, out int lpFileSizeHigh);

    // Define locals.
    private bool _disposed = false;
    private readonly SafeFileHandle _safeHandle;
    private readonly int _upperWord;

    public DisposableStreamResource(string fileName)
    {
        if (string.IsNullOrWhiteSpace(fileName))
        {
            throw new ArgumentException("The fileName cannot be null or an empty string");
        }

        _safeHandle = CreateFile(
            fileName, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);

        // Get file size.
        Size = GetFileSize(_safeHandle, out _upperWord);
        if (Size == INVALID_FILE_SIZE)
        {
            Size = -1;
        }
        else if (_upperWord > 0)
        {
            Size = (((long)_upperWord) << 32) + Size;
        }
    }

    public long Size { get; }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        // Dispose of managed resources here.
        if (disposing)
        {
            _safeHandle?.Dispose();
        }

        // Dispose of any unmanaged resources not wrapped in safe handles.

        _disposed = true;
    }
}

 

DisposeAsync() 

 无参数的 DisposeAsync() 方法在 await using 语句中隐式调用,它具有标准实现:

public async ValueTask DisposeAsync()
{
    // Perform async cleanup.
    await DisposeAsyncCore();

    // Dispose of managed resources.
    Dispose(false);
    // Suppress finalization.
    GC.SuppressFinalize(this);
}

因此,调用 Dispose(false) 而非 Dispose(true)

using System;
using System.Text.Json;
using System.Threading.Tasks;

public class ExampleAsyncDisposable : IAsyncDisposable, IDisposable
{
    // To detect redundant calls
    private bool _disposed = false;

    // Created in .ctor, omitted for brevity.
    private Utf8JsonWriter _jsonWriter;

    public async ValueTask DisposeAsync()
    {
        await DisposeAsyncCore();

        Dispose(false);
        GC.SuppressFinalize(this);
    }

    protected virtual async ValueTask DisposeAsyncCore()
    {
        // Cascade async dispose calls
        if (_jsonWriter != null)
        {
            await _jsonWriter.DisposeAsync();
            _jsonWriter = null;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        if (disposing)
        {
            _jsonWriter?.Dispose();
            // TODO: dispose managed state (managed objects).
        }

        // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
        // TODO: set large fields to null.

        _disposed = true;
    }
}

 

堆叠的 using

为了帮助防止潜在的问题,应避免堆叠,并遵循以下示例模式:

class ExampleProgram
{
    static async Task Main()
    {
        var objOne = new ExampleAsyncDisposable();
        await using objOne.ConfigureAwait(false);
        // Interact with the objOne instance.

        var objTwo = new ExampleAsyncDisposable();
        await using objTwo.ConfigureAwait(false))
        {
            // Interact with the objTwo instance.
        }

        Console.ReadLine();
    }
}

 

StreamReader 对象以读取两个不同文件的内容。

using StreamReader version1 = new StreamReader("file1.txt"),
                           version2 = new StreamReader("file2.txt");

 

相关文章:

  • 2021-08-23
  • 2022-01-22
  • 2022-12-23
  • 2021-08-17
  • 2021-08-24
猜你喜欢
  • 2022-02-18
  • 2021-07-18
  • 2022-12-23
  • 2022-12-23
  • 2022-02-23
  • 2021-10-03
相关资源
相似解决方案