如何处理在Linq表达式中创建的IDisposable对象?

5

Linq允许您在查询表达式中创建新对象。当您有封装列表生成的类时,这非常有用。我想知道如何处理需要释放的创建的对象?

示例:

class Generator
{
    public IEnumerable<int> Gen(int size)
    {
        return Enumerable.Range(0, size);
    }
}

class bar
{
    public void doit()
    {
        var foo =
            from r in Enumerable.Range(1, 3)
            from g in new Generator().Gen(r)
            select g;
    }
}

这将创建3个生成器对象,它们在某个时候将被垃圾回收。如果Generator是IDisposable的,我如何获得Dispose()调用?


非常好的问题。我有同样的问题,只是我在使用let关键字。 - Marcel
2个回答

5

听起来你不应该在每次迭代中创建新的Generator对象,原因如下:

  • 重复快速地分配(和可能释放)内存非常低效。
  • Generator对象可能仅为给定参数集生成值的一个实例。当然,如果需要,请澄清。

我建议你尝试以下方法:

using (var gen = new Generator())
{
    var foo =
        from r in Enumerable.Range(1, 3)
        from g in gen.Gen(r)
        select g;
}

没错,但这有点绕过了标题问题。 - H H
1
@Henk:的确如此,但我认为无论如何,OP都是在错误的方向上思考。 :) - Noldorin
如果我只创建了一个需要处理的对象,这将起作用。我承认我的示例没有显示出需要,但可以假定真实类更加复杂。通常情况下,我希望在查询循环的每次迭代中创建一个新的可处理对象。 - Jason
好的,在这种情况下,你可以使用Marc展示的扩展方法来解决问题。 - Noldorin

5

好的,我希望这只是巧合,但是:SelectMany; combining IDisposable and LINQ,通过自定义的SelectMany实现,可以实现以下功能:

    var foo =
        from r in Enumerable.Range(1, 3)
        from gen in new Generator()
        from g in gen.Gen(r)
        select g;

(请注意,我假设有一个合理的原因来执行这个操作))

SelectMany

或者使用Using()扩展方法(而不是SelectMany):
    var foo =
        from r in Enumerable.Range(1, 3)
        from gen in new Generator().Using()
        from g in gen.Gen(r)
        select g;

Using


你的博客文章发布时间非常完美。我想在Linq代码中使用DirectoryEntry等对象,但不想留下未被释放的操作系统资源。 - Jason
@Mark,是否有办法对Select也这样做?我试过了,但似乎它“隐藏”了内置函数,并且不允许我选择任何非IDisposable的东西... - Benjol
@Benjol - 你能提供更多信息吗?你选择的来源是什么? - Marc Gravell
@Mark,将其制作成问题,并且这几乎是重复的,所以您可能想在这里回答... https://dev59.com/ok7Sa4cB1Zd3GeqP5aqD - Benjol

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