在 Linq 中处置 IDisposable

发布于 2024-09-07 12:34:08 字数 1708 浏览 9 评论 0原文

(这是对 这个问题)

在我发布该问题 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 对我上面提到的问题的回答,我想知道是否可以直接重载 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; }
    }
}

(This is a follow on from a comment on an answer to this question)

18 months after I posted it, someone spotted a bug in one of my Linq examples, where I use an IDisposable half way through a method chain, which never gets disposed.

I attempted to write an extension method to handle this:

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);

After seeing Marc's answer to the question I referenced above, I wondered if I could overload the Select extension method directly, but if I do (by renaming Using to Select), the compiler squeals about Select(d => d.Id), because There is no implicit conversion from 'string' to 'System.IDisposable'.

Here's a test class...

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; }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

ま昔日黯然 2024-09-14 12:34:08

像这样吗?除了构造函数的使用之外,我在这里并没有真正改变太多......

    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 操作。

Like so? I haven't really changed much here, except the constructor usage...

    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;
    }

However! The thing to watch here is that we don't introduce any conflicting LINQ operations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文