类是否应该同时实现IAsyncDisposable和IDisposable接口?

13
例如,我有这个类:
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();
}

同时使用异步和同步方法是否正确?如果我在ASP.NET Core中使用DI,哪种方法将在处理器释放时被调用。

2个回答

9

何时应该只实现 IDisposable 接口?

IDisposable 是更标准且默认的接口,自早期以来几乎被所有框架支持。如果您的类或其派生类不需要异步释放资源,则考虑仅实现 IDisposable。例如,SemaphoreSlim 就没有实现 IAsyncDisposable

什么情况下可以仅实现 IAsyncDisposable 接口?

注意:这主要适用于您控制或了解对象如何被实例化和销毁的情况。例如,如果您正在编写一个可执行文件(而不是库),则会更多地掌控整个环境和代码的命运。

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

何时应同时实现 IAsyncDisposableIDisposable 接口?

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

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

为什么?

  1. 依赖注入框架可能会或可能不会支持 IAsyncDisposable。当然,大多数支持,但并非所有依赖注入系统都是平等的。如果您正在编写一个库,则无法知道对象将如何创建。
  2. 如果您的代码运行在容器内,并且容器同步关闭,则可能会抛出异常(对于 .NET Core 依赖注入系统而言是真的)。
  3. 创建对象后再阻塞 DisposeAsync 并不太干净。调用者的释放调用将更像 yourDisposableObject.DisposeAsync().GetAwaiter().GetResult()

以下是来自官方 Microsoft MSDN 的引用。

通常,在实现 IAsyncDisposable 接口时,类也会实现 IDisposable 接口。IAsyncDisposable 接口的良好实现模式是准备好同步或异步释放。实现销毁模式的所有指导也适用于异步实现。

其他次要建议:如果您预见到类的派生类可能需要处理需要释放资源的情况,则考虑将您的 Dispose()DisposeAsync() 实现为虚拟方法。否则,考虑使您的类 sealed

好的例子

  1. Stephen Toub的二进制写入器类

参考资料

  1. Alistair Evans博客
  2. MSDN
  3. Code Therapist

3

无论您的AspNetCore问题是什么,一个类中同时实现同步和异步方法是完全可以的。

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

参见这里


1
那么我应该写 UnitOfWork : IUnitOfWork,IDisposable,IAsyncDisposable 对吧?此外,框架将使用哪种方法进行处理? - Anon Anon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接