Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mutable wrapper of value types to pass into iterators

I'm writing an iterator that needs to pass around a mutable integer.

public IEnumerable<T> Foo(ref int valueThatMeansSomething)
{
    // Stuff

    yield return ...;
}

This nets me "Error 476 Iterators cannot have ref or out parameters".

What I need is this integer value to be modified in the iterator and usable by the caller of the iterator. In other words, whatever calls Foo() above wants to know the end value of valueThatMeansSomething and Foo() may use it itself. Really, I want an integer that is a reference type not a value type.

Only thing I can think of is to write a class that encapsulates my integer and permits me to modify it.

public class ValueWrapper<T>
    where T : struct
{
    public ValueWrapper(T item)
    {
        this.Item = item;
    }

    public T Item { get; set; }
}

So:

ValueWrapper<int> w = new ValueWrapper<int>(0);
foreach(T item in Foo(w))
{
    // Do stuff
}

if (w.Item < 0) { /* Do stuff */ }

Is there any class or mechanism to handle this already in the BCL? Any flaws with ValueWrapper<T> proposed above?

(My actual use is more complicated than the example above so handling the variable inside my foreach loop that calls Foo() is not an option. Period.)

like image 533
Colin Burnett Avatar asked Jun 26 '09 18:06

Colin Burnett


2 Answers

If you only need to write the value then another technique would be:

public IEnumerable<whatever> Foo(Action<int> setter) { ... }

int value = 0;
foreach(var x in Foo(x => {value=x;}) { ... }

Coincidentally, I'll be doing a series on the reasons why there are so many goofy restrictions on iterator blocks in my blog in July. "Why no ref parameters?" will be early in the series.

http://blogs.msdn.com/ericlippert/archive/tags/Iterators/default.aspx

like image 152
Eric Lippert Avatar answered Nov 15 '22 03:11

Eric Lippert


Nope, I'm pretty confident there's nothing existing in the BCL that can do this. Your best option is precisely what you have proposed I think. The implementation of ValueWrapper really need not be any more complicated than what you have proposed.

Of course, it's not guaranteed to be thread-safe, but if you need that you can simply convert the automatic property into a standard one with a backing variable and mark the field as volatile (to insure the value is up-to-date at all times).

like image 40
Noldorin Avatar answered Nov 15 '22 05:11

Noldorin