【问题标题】:What does "Access to disposed closure" mean?“访问已处置的闭包”是什么意思?
【发布时间】:2014-01-11 00:50:51
【问题描述】:

我有以下代码:

public void DequeueRecipe(AuthIdentity identity, params Guid[] recipeIds)
{
   using (var session = GetSession())
   {
      var recipes = (from r in recipeIds select new Models.Recipes {RecipeId = r}).ToArray();

      var dbRecipes = session.QueryOver<Models.QueuedRecipes>()
         .Where(Expression.Eq("UserId", identity.UserId))
         .Where(Expression.InG("Recipe", recipes))
         .List<Models.QueuedRecipes>();

      using (ITransaction transaction = session.BeginTransaction())
      {
         dbRecipes.ForEach(r => session.Delete(r)); // <-- Warning
         transaction.Commit();
      }
   }
}

reSharper 给了我警告:

访问已处置的闭包

上线:

dbRecipes.ForEach(r => session.Delete(r));

session 变量下划线是罪魁祸首)。

虽然ForEach 方法确实采用了在变量session 周围创建闭包的lamba 表达式,但我看不到在执行此代码时可能会释放它的方法。也许 reSharper 认为 ForEach 可能会并行执行某种任务,或者将 Action&lt;&gt; 保存到以后,因此从技术上讲,它可能会在匿名函数在内存中仍然可以访问时被释放。

忽略此警告是否安全?有没有办法可以重新格式化我的代码以防止出现此警告?这段代码确实存在危险吗?

我已经习惯了 reSharper 比我更聪明,所以我想确切地了解发生了什么。

【问题讨论】:

  • 无关:事务开始/提交不是Delete()的责任吗?在事务之外执行 Delete() 是否可能/正确(假设它有多个操作 [表])?
  • @MitchWheat - 同意,我可以删除事务,因为它会在会话结束时全部提交。我一直在修改我的会话代码,所以这是我早期架构的残余。
  • 当我使用这个批处理代码 sn-p 将 IEnumerable 分组为大小为 x 的批次时,我也遇到了这个错误:stackoverflow.com/a/44505349/1040437 我的老板在 Resharper 中看到了警告并翻转了出来。但据我所知,这是完全安全的代码。

标签: c# closures resharper


【解决方案1】:

因为session 被包装在 using 语句中,并且 LINQ 执行可以推迟到它被枚举为止。

Resharper 警告说这可能会导致异常,因为在枚举 dbRecipes 时,session 可能已被释放。

说实话:我不确定上面的代码是否会像警告的那样失败。

【讨论】:

  • ForEach 应该立即枚举dbRecipes,对吧?所以什么都不应该被推迟。
  • 那么您不认为这是对 ReSharper 的错误警告吗? session 真的可以在该代码中处理吗?我从未见过我的代码表现得那样。根据我对using 声明的理解,ReSharper 是错误的。
  • 如果添加 .ToList() 来评估 dbrecipes 会发生什么?
  • @MitchWheat - 如果我这样做,警告就会消失。因此,reSharper 足够聪明,知道当时肯定会枚举列表,但还不够聪明,无法看到 dbRecipesGuid[],因此无论如何都不能推迟枚举。
  • 我认为这只是出于谨慎的考虑。另外它知道 .List() 是什么吗?
猜你喜欢
  • 2013-10-15
  • 2023-02-22
  • 1970-01-01
  • 2015-11-27
  • 2013-04-10
  • 1970-01-01
  • 2018-07-17
  • 1970-01-01
  • 2016-03-07
相关资源
最近更新 更多