tags:

views:

79

answers:

2

Linq allows you to create new object inside of a query expression. This is useful when you have classes that encapsulate generation of a list. I’m wondering how you dispose of objects that are created that need it?

Example:

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

This will create 3 Generator objects that will be garbage collected at some point. If Generator was IDisposable how would I get the Dispose() call?

+5  A: 

Doesn't sound like you should be creating a new Generator object on each iteration, for a couple of reasons:

  • It's horribly inefficient to allocate (and potentially deallocated) memory repeatedly and rapidly.
  • The Generator object is probably designed for only one instance to generate values for a given set of parameters. Of course, I may be wrong on this, so please clarify if necessary.

I recommend you try the following:

using (var gen = new Generator())
{
    var foo =
        from r in Enumerable.Range(1, 3)
        from g in gen.Gen(r)
        select g;
}
Noldorin
Right, but that sidesteps the title question a little.
Henk Holterman
@Henk: Indeed it does, but I think the OP is looking at things the wrong way anyway. :)
Noldorin
This would work if I only created 1 object that needed to be disposed. I admit my example didn't show a need, but you can assume the real classes are more complex. Normally I want to create a new disposable object each iteration of the query loops.
Jason
Fair enough, in that case you have your solution in the form of an extension method shown by Marc.
Noldorin
+4  A: 

OK; I'm hoping this is coincidence, but: SelectMany; combining IDisposable and LINQ, which (with the custom SelectMany implementation) would allow:

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

(note that I'm assuming there is a sensible reason to do this per r)

SelectMany

or with the Using() extension method (instead of 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

Marc Gravell
Your blog post was perfectly timed. I want to use objects such as DirectoryEntry inside of Linq code but didn't want to leave OS resources left unclaimed.
Jason
@Mark, is there anyway to do this for Select as well? I've tried, but it seems to 'hide' the built-in function and won't let me select anything which *isn't* IDisposable...
Benjol
@Benjol - can you provide more info? What is the source that you are selecting from?
Marc Gravell
@Mark, made a question out of it, it's an almost duplicate, so you might want to answer here... http://stackoverflow.com/questions/3116927/disposing-an-idisposable-in-linq
Benjol