【问题标题】:Should Class Implement Both IAsyncDisposable and IDisposable?类应该同时实现 IAsyncDisposable 和 IDisposable 吗?
【发布时间】:2020-05-28 21:22:43
【问题描述】:

例如我有这个类:

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-core dependency-injection idisposable unit-of-work


    【解决方案1】:

    什么时候应该只实现IDisposable

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

    什么时候可以只执行IAsyncDisposable

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

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

    什么时候应该同时实现IAsyncDisposableIDisposable

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

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

    为什么?

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

    这是来自微软官方MSDN的引用。

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

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

    好例子

    1. Stephen Toub's Binary Writer class

    参考文献

    1. Alistair Evans blog
    2. MSDN
    3. Code Therapist

    【讨论】:

      【解决方案2】:

      不管您对 AspNetCore 有什么顾虑; 是的,在一个类中同时实现 Sync 和 Async 方法是完全可以的。

      但是,拥有接口链(一个接口要求实现另一个接口)被认为不是干净的代码。

      this

      【讨论】:

      • 那么我应该写UnitOfWork : IUnitOfWork, IDisposable, IAsyncDisposable,对吧?框架将使用什么方法进行处理?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-09
      • 2011-01-30
      • 2021-06-26
      • 1970-01-01
      • 2010-09-11
      相关资源
      最近更新 更多