在Linq中处理IDisposable对象

4

(这是对this问题的答案评论的后续)

18个月后,有人发现了一个错误,在我的Linq示例之一中,我在方法链的中途使用了一个IDisposable,但它从未被处理。

我试图编写一个扩展方法来解决这个问题:

public static IEnumerable<R> Using<T, R>(
     this IEnumerable<T> list, Func<T, R> selector) where R : IDisposable
{
    foreach(var item in list)
        using(var disposable = selector(item))
            yield return disposable;
}

var q = Enumerable.Range(0, 10)
        .Using(i => new Disposable(i))
        .Select(d => d.Id);

在看到我参考的问题中Marc's answer的回答后,我想知道是否可以直接重载Select扩展方法,但如果我这样做(通过将Using重命名为Select),编译器会抱怨Select(d => d.Id),因为'string'无法隐式转换为'System.IDisposable'
这是一个测试类...
public class Disposable : IDisposable
{
    private string _id;
    private bool _disposed = false;
    public Disposable(int id)
    {
        Id = id.ToString();
        Console.WriteLine("Creating " + Id);
    }
    public void Dispose()
    {
        Console.WriteLine("Disposing " + Id);
        _disposed = true;
    }
    public string Id 
    { 
        get 
        {
            if(_disposed) throw new Exception("Call to disposed object!");
            return _id; 
        }
        set { _id = value; }
    }
}
1个回答

1

这样做可以吗?我在这里并没有做太多的更改,只是改变了构造函数的使用方式...

    static void Main()
    {
        var q = from d in System.Linq.Enumerable.Range(0, 10)
                select new Disposable(d);
    //  alternatively:
    //  var q = System.Linq.Enumerable.Range(0, 10)
    //          .Select(d => new Disposable(d));

        foreach(var item in q)
        {
            Console.WriteLine("Hi");
        }
    }
    public static IEnumerable<R> Select<T, R>(
        this IEnumerable<T> list, Func<T, R> selector) where R : IDisposable
    {
        foreach (var item in list)
            using (var disposable = selector(item))
                yield return disposable;
    }

然而!需要注意的是,我们不要引入任何冲突的LINQ操作。


2
那么我的扩展方法隐藏了内置的方法,所以我基本上“破坏”了Select方法的任何其他用途?我原以为编译器能够区分它们。你的SelectMany方法也有同样的问题吗? - Benjol

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