C# yield return using same reference

796 views Asked by At

I have a problem with my iterator in C# which I can't seem to resolve. Here are the two relevant methods (simplified for the purposes of the question):

protected virtual IEnumerable<T> Iterator()
{
    // Code here omitted for brevity

    foreach(object row in compiler.ResultsIterator())
    {
        Model obj;

        object[] row_array = new object[fields_length];
        // Logic to set row_array values omitted for brevity
        obj = _model.Clone(); // Does a MemberwiseClone
        obj.SetFieldValues(row_array);
        yield return (T)(obj as object);
    }
}

private void FillCache()
{
    IEnumerator<T> _iter = Iterator().GetEnumerator();
    while(_iter.MoveNext())
    {
        ResultCache.Add(_iter.Current);
    }
}

The issue is that on the first iteration in FillCache() ResultCache contains an object, let's call it 'Object 1' but on the second iteration it contains 'Object 2' twice. Clearly the problem is that the variable 'obj' is passed by reference and is not being created new even though it is declared inside the foreach loop.

So my question is how can I create a new 'obj' reference each time?

2

There are 2 answers

1
Robin Elvin On BEST ANSWER

Ok, I feel bad about misleading with the yield problem but the issue is a question of references. It turns out the real problem is the MemberwiseClone because this is only a shallow copy so all the deep member references are the same.

Therefore the answer is that the Clone() method should perform a deep copy.

4
dcastro On

If you're able to compile that code and we aren't, there's only one possible explanation: you have a field named obj, and the local variable obj shadows the field.

If that is so, returning the field obj would explain why you get the same reference on every iteration