user1675891
user1675891

Reputation:

How to refer to the actual element in foreach?

I used the following code to step through an IEnumerable.

IEnumerable<Thing> things = ...;
foreach (Thing thing in things)
  thing = method(thing);

The compiler disagrees with it since I'm referring to thing that is the iterating variable. Of course, I intend to affect the underlying object in my list, instead. How do I do that?

For now, I went with the work-around using a numerated iteration but there are two issues there. For one, it's not good coding IMHO. Besides that, it requires me to change my things from IEnumerable to IList (or should I even be using List?!), which will bite be in my lower back when things get big.

//List<Thing> things = ...;
IList<Thing> things = ...;
for (int i = 0; i < things.Count(); i++)
  things[i] = method(things[i]);

Upvotes: 1

Views: 215

Answers (5)

Item replacement can be easy done using some collection, for example, array or List<T> (as you described) by using for loop (not foreach).

There is no way to replace the object using foreach statement.

If you really want to use IEnumerable<T> interface there are two alternatives:

  1. Transform the sequence of Things (see IEnumerable<T>.Select() method). The source sequence and source instances of Thing are not modified in this case.

    For example:

    var newThings = things.Select(t => new Thing(/* pass different values using original t instance */));
    
  2. Update the state of each instance:

    class Thing
    {
        public void UpdateState(/* parameters */)
        {
            // Update field/property values, etc.
        }
    }
    
    ...        
    
    foreach (var thing in things)
        thing.UpdateState(/* new values */);
    

Upvotes: 1

LukeHennerley
LukeHennerley

Reputation: 6434

If the length of the IEnumerable will reamin the same, I would use ToArray() and iterate with a for loop.

For example:

char[] chars = "somestring".ToArray();
for (int i = 0; i < chars.Length; i++)
{
  chars[i] = SomeMethod();
}

For modifying something in the collection.

Thing[] things = ...;
for (int i = 0; i < things .Length; i++)
{
  AddOne(ref things[i]);
}

public void AddOne(ref Thing t)
{
  t.Foo += 1;
}

Upvotes: 0

krypton-io
krypton-io

Reputation: 713

you cant change the references when iterating items inside list since its restricted in enumerators but you can change objects inside items....

use powerful LINQs or just clone your list like ToList() or ToArray().

Upvotes: 1

Oliver
Oliver

Reputation: 9002

If you are going to run the method on all elements, why don't you transform the whole collection:

public IEnumerable<Thing> TransformThings(IEnumerable<Thing> input)
{
    foreach (var thing in input)
        yield return method(thing);
}

You can use it like this:

var transformedThings = TransformThings(things);

This will transform each element as you iterate over the collection, meaning you don't have to enumerate the whole collection to memory.

EDIT

Even SIMPLER:

var transformedThings = things.Select(thing => method(thing));

Upvotes: 2

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236208

You can project sequence with Linq:

 var transformedThings = things.Select(t => method(t));

Upvotes: 4

Related Questions