我有类似以下设置的内容:

class DisposableContainer : IDisposable
{
  IEnumerable<DisposableObject> items;

  //Potential problem method
  public void Populate(IEnumerable<OtherThings> things)
  {
    items = things.Select(thing => new DisposableObject(thing));
  }

  //IDisposable Implementation
  private bool disposed = false;
  ~DisposableContainer()
  {
    Dispose(false);
  }

  public override void Dispose()
  {
    Dispose(true);

    GC.SuppressFinalize(this);
  }

  private void Dispose(bool disposing)
  {
    if (!disposed)
    {
      if (disposing)
      {
        if (items != null)
        {
          items.Select(item => item.Dispose());
        }
      }

      disposed = true;
    }
  }
}


假定DisposableObject正确实现IDisposable,并具有接受类型为OtherThing的参数的构造函数。

假设在Populate方法中,如果select调用的第三次迭代引发异常,那么成功创建的前两个DisposableObject会发生什么?我假设它们泄漏了并且没有被处置。

后续问题:有没有办法在仍然使用Linq生成IEnumerable<>的同时安全地处理上述情况?我无法预见,但我想抛弃这个主意,看看是否有人有想法。

最佳答案

您的假设是正确的。已经创建的DisposableObject将无法正确处理。

您可以通过使用一个临时列表来修复它,该列表包含创建的项目,并在需要时将其处置:

public void Populate(IEnumerable<OtherThings> things)
{
    var temp = new List<DisposableObject>();
    try
    {
        temp.AddRange(things.Select(otherThing => new DisposableObject(otherThing)));
        items = temp;
    }
    catch
    {
        foreach (var disposableObject in temp)
        {
            disposableObject.Dispose();
        }
        throw;
    }
}


这不能通过使用现有的Linq扩展方法来完成,但是您可以(但不建议这样做)添加自己的扩展方法:

public static IReadOnlyCollection<TDisposable> SelectDisposables<TItem, TDisposable>(
    this IEnumerable<TItem> enumerable,
    Func<TItem,TDisposable> selector)
    where TItem : IDisposable
    where TDisposable : IDisposable
{
    var temp = new List<TDisposable>();
    try
    {
        temp.AddRange(enumerable.Select(selector));
        return temp;
    }
    catch
    {
        foreach (var disposable in temp)
        {
            disposable.Dispose();
        }
        throw;
    }
}


可以这样使用:

items = things.SelectDisposables(thing => new DisposableObject(thing));

关于c# - 在Linq内部创建的IDisposable-异常安全,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28551727/

10-16 16:42