首页 > 解决方案 > 类应该同时实现 IAsyncDisposable 和 IDisposable 吗?

问题描述

例如我有这个类:

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();
    }
}

使用这样的接口:

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

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

标签: c#asp.net-coredependency-injectionidisposableunit-of-work

解决方案


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

IDispoable是更标准和默认的接口,从一开始或之后几乎所有框架都支持。如果您的类或您的类的派生类不需要异步释放资源,则只考虑实现IDisposable. 例如,SemaphoreSlim不实现IAsyncDisposable.

什么时候可以只执行实施IAsyncDisposable

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

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

什么时候应该同时实现IAsyncDisposableand IDisposable

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

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

为什么?

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

这是来自官方 Microsoft MSDN的引述。

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

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

好例子

  1. Stephen Toub 的 Binary Writer 课程

参考

  1. 阿利斯泰尔·埃文斯博客
  2. MSDN
  3. 代码治疗师

推荐阅读