【问题标题】:Is it good practice to pass an already instanciated property into a using statement?将已经实例化的属性传递给 using 语句是一种好习惯吗?
【发布时间】:2019-09-27 06:24:12
【问题描述】:

我在重构一些严重依赖 Disposable 模式的代码时遇到了这个问题。

我确实有一个只读字段 DbContext,它在构造函数中被初始化。现在我想知道是否可以将字段传递到 using 块中以正确处理它。或者我是否必须摆脱字段和初始化才能在每个 using 块中初始化它

protected readonly DbContext _context;

public Repository(DbContext context)
{
    _context = context;
}

public Task<T> GetAsync(Guid id)
{
    using (_context)
    {
        return _context.Set<T>().FindAsync(new CancellationToken(), id);
    }
}

我希望以正确的方式应用 Dispose 模式

【问题讨论】:

  • 这没什么错,但是将 EF 包装在存储库中要糟糕得多,并且传入并缓存数据库上下文并自动处理它绝对是一种罪过
  • 有一个简单的规则,如果你创建了它就必须丢弃它,如果你不创建它就不要丢弃它。
  • @MongZhu 该语句应该是 "将 EF 包装在存储库中;将 dbcontext 传递到缓存;然后自动神奇地处理它会更糟糕(也是一种罪过)" 表示所要求的语言功能没有任何问题,但是 EF 上的存储库一开始就是一种代码味道,而使用一次性资源做神奇的意想不到的事情显然是代码审查失败并导致重新考虑整个问题
  • @TheGeneral 感谢您的评论。找到this nice article(我猜)对您的评论有很好的解释/阐述。
  • @MongZhu 是的,基本上说得比我好,很好发现

标签: c# properties using readonly


【解决方案1】:

我发现有两个潜在问题:

  1. 当您退出using 块时,对象将被释放。如果您随后尝试重复使用它,您可能会在某处得到InvalidOperationException
  2. 某些对象在处置时不会释放其所有托管资源。他们可能仍在引用一些大型对象,当您引用一次性对象时,这些对象不能被垃圾收集。恰当的例子:MemoryStream - 当你处理它时,MemoryStream 不会取消引用它的内部byte[] 缓冲区。这意味着,除非您取消引用流本身,否则无法收集数组并且实际上是内存泄漏。

所以从我的角度来看,最好在using 语句中创建一个新对象,因为它会自动为您处理它,并且 取消引用它以便可以收集它。

一种可能的解决方案是注入一个工厂对象,并使用其工厂方法在using 块的开头创建一次性对象。

【讨论】:

  • 如果你必须在类实例的生命周期内保留引用,你的类应该实现IDisposable
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
  • 1970-01-01
  • 2017-06-21
  • 2014-11-05
  • 1970-01-01
  • 2015-09-02
相关资源
最近更新 更多