2

I had this code :

foreach (object obj in _Destinations)
{
    obj = _ItemsSource;
}

which was generating the error

Cannot assign to 'obj' because it is a 'foreach iteration variable'

So I "circled" the problem with the following code :

for (int i = 0; i < _Destinations.Count; i++)
{
    _Destinations[i] = _ItemsSource;
}

This works on my actual cases but I'm not sure that this is the exact same thing for any type of object. Is that the case ?

EDIT : _Destinations is a List<object>

Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
Guillaume Slashy
  • 3,554
  • 8
  • 43
  • 68
  • This thread might be of interest as to why `foreach` loops behave differently to `for` loops: http://stackoverflow.com/questions/5650705/in-c-why-cant-i-modify-the-member-of-a-value-type-instance-in-a-foreach-loop – keyboardP Dec 22 '11 at 13:12

5 Answers5

2

This is definitely not the same exact thing: for starters, the second one works, while the first one does not :)

The reason the first snippet does not work is because it uses an iterator from the _Distance list, and it is not possible to assign to the original collection through IEnumerable<T>'s iterator. The second snippet uses [index] to access the underlying list or array. This construct allows reading and writing; that's why it works.

As far as accessing all elements of the list or array in the same order is concerned, both constructs are identical.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Yeah of course, my question was more "if the 1st code could compile, will the second be a strict equivament ?" :) Semms to be "yes" so that's cool :) – Guillaume Slashy Dec 22 '11 at 13:15
  • @GuillaumeSlashy it would be equivalent only logically. Under the hood, the first piece of code does not use indexing, even when the collection allows it. To put it another way, if you use lists, there is no difference; if you implement your own lists, there is a significant difference. – Sergey Kalinichenko Dec 22 '11 at 13:21
  • I'll use Lists, ObservableCollections and IEnumerables. So this is equivalent ? – Guillaume Slashy Dec 22 '11 at 13:26
  • @GuillaumeSlashy Lists and ObservableCollections have an indexer method `myList[index]`, so it is going to work for them. IEnumerables, on the other hand, do not have an indexer, so your second snippet is not going to compile if the only thing known about your collection is that it is IEnumerable. – Sergey Kalinichenko Dec 22 '11 at 13:30
  • ok will keep it in mind, thanks :) – Guillaume Slashy Dec 22 '11 at 13:40
1

I guess _Destinations is a collection of value types.

The forach loop creates a copy of the element it iterates for each "round" of the loop, and you end up only changing the copy, with no change to the actual collection that you are iterating.

In the for loop you are changing the actual collection by using the index.

So no, they are not strictly equivalent.

For reference types this is not matter in the same sense since both the element in the collection and the copy created by the foreach reference the same object, and the correct object will be altered regardless if you use the foreach or for loop (at least when you use it like this)

Øyvind Bråthen
  • 59,338
  • 27
  • 124
  • 151
  • downvoter, care to elaborate? – Øyvind Bråthen Dec 22 '11 at 13:15
  • Why would you guess it is a collection of value types? If you had a collection of class object Foos, reassigning the loop variable would be no less illegal. And even if it was not illegal, reassigning to a variable of a reference type inside the loop would *still* not reflect inside the collection. – Anthony Pegram Dec 22 '11 at 13:17
1

It's obviously not the same thing, as your results are different! One gets an error, the other works.

Sidestepping that difference, your first error is the result of it being illegal to modify the loop variable in a foreach. Your second manages to sidestep the problem entirely by iterating in a for and assigning to the index position. This will continue to work for you as long as you have an writable, indexable collection such as a list or an array. If you are working with a non-writable or non-indexable collection, such as a simple IEnumerable or a ReadOnlyCollection<T>, then you will not be able to use this mechanism to overwrite the elements, as the sequence is readonly.

Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
1

Foreach works on any IEnumerable, which is the most basic contract for an object which is some kind of aggregate, list, collection, ... of some other objecs. IEnumerable does not provide facilities to override items in the aggregate, not even adding or removing. In IEnumerable there is also no notion of an index. Therefore you can't assign a value to the foreach iteration variable.

The other code snippet requires a collection which implements IList which is a more specific contract, one which allows for collection manipulation and has also a notion of an index. Therefore the second code snippet works.

The IList in the second example could theoretically implement an enumeration which does not enumerate in index-ascending order, but this is very unlikely, so you can consider both iteration techniques as the same.

Oliver Hanappi
  • 12,046
  • 7
  • 51
  • 68
0

you should read about IEnumerable and IEnumerator to get your foreach block to work correctly.

IROEGBU
  • 948
  • 16
  • 33