类应该同时实现 IAsyncDisposable 和 IDisposable 吗?

Ano*_*non 6 c# dependency-injection idisposable unit-of-work asp.net-core

例如我有这个类:

public class UnitOfWork : IUnitOfWork
{
    private readonly ApplicationDbContext _context;

    public IProductRepository Products { get; private set; }
    public ICategoryRepository Categories { get; private set; }
    public IPhotoRepository Photos { get; private set; }

    public UnitOfWork(ApplicationDbContext context, IProductRepository productRepository,
        ICategoryRepository categoryRepository, IPhotoRepository photoRepository)
    {
        _context = context;
        Products = productRepository;
        Categories = categoryRepository;
        Photos = photoRepository;
    }

    public int Complete()
    {
        return _context.SaveChanges();
    }

    public Task<int> CompleteAsync()
    {
        return _context.SaveChangesAsync();
    }

    public void Dispose()
    {
        _context.Dispose();
    }

    public async ValueTask DisposeAsync()
    {
        await _context.DisposeAsync();
    }
}
Run Code Online (Sandbox Code Playgroud)

使用这样的接口:

public interface IUnitOfWork : IDisposable, IAsyncDisposable
{
    IProductRepository Products { get; }
    ICategoryRepository Categories { get; }
    IPhotoRepository Photos { get; }
    int Complete();
    Task<int> CompleteAsync();
}
Run Code Online (Sandbox Code Playgroud)

同时拥有 Async 和 Sync 方法是否正确?例如,如果我在 asp net core 中使用 DI,那么在处理过程中会调用什么方法。

use*_*932 9

你应该只在什么时候实施IDisposable

IDispoable是更标准和默认的接口,并且从一开始或此后不久就受到几乎所有框架的支持。如果您的类或您的类的派生类不需要异步释放资源,那么请考虑仅实现IDisposable. 例如,SemaphoreSlim不实现IAsyncDisposable.

什么时候你可以只依靠实施来摆脱困境IAsyncDisposable

注意:这更适用于您可以控制或知道如何实例化和销毁对象的情况。例如,如果您正在编写可执行文件(而不是库),您可以更好地控制整体环境和代码的命运。

IAsyncDisposable如果您预见您的类或您的类的派生类将需要或可能需要异步释放资源,您应该实现。

什么时候应该同时实施IAsyncDisposableIDisposable

注意:以下内容更多地适用于库的最佳实践和推荐方法,因为它们通常无法控制创建库中定义的类型实例的代码。

理想情况下,您应该同时实现IAsyncDisposableIDisposable。换句话说,IAsyncDisposable不应被视为IDisposable.

为什么?

  1. 依赖注入框架可能支持也可能不支持IAsyncDisposable。当然,大多数依赖注入系统都是如此,但并非所有依赖注入系统都是一样的。如果您正在编写一个库,您不知道如何创建您的对象。
  2. 如果您的代码在容器内运行并且容器是同步处置的,则可能会引发异常(对于 .NET Core 依赖注入系统来说是这样)。
  3. 创建一个对象然后阻塞 aDisposeAsync以使其同步并不那么干净。调用者的 dispose 调用将更像yourDisposableObject.DisposeAsync().GetAwaiter().GetResult().

这里引用的是微软官方MSDN

通常,在实现 IAsyncDisposable 接口时,类也会实现 IDisposable 接口。IAsyncDisposable 接口的一个良好实现模式是为同步或异步处置做好准备。所有用于实现处置模式的指南也适用于异步实现。

其他次要建议:如果您预见类的派生类将具有可能需要处置的资源,请考虑将Dispose()和实现为虚拟的。DisposeAsync()否则,请考虑制作您的课程sealed

好例子

  1. Stephen Toub 的二进制编写器课程

参考

  1. 阿利斯泰尔·埃文斯博客
  2. 微软软件定义网络
  3. 代码治疗师