0

Here is a piece of code:

public class Schema
{
    public Schema(List<CountryParticipantsStages> places)
    {
        Places = places.Select(participant =>(AbstractGeneralParticipants) new GeneralParticipants(participant)).ToList();
    }
...

Order of element in source and result lists will be the same if source list is iterated in full. But if if 'Schema' constructor is called in the middle of any iteration then order of elements in 'Places' list will be shifted...

To avoid this I see the only way to use not a 'Select' method but a 'for' loop that will go from 0th element:

public class Schema
{
    public Schema(List<CountryParticipantsStages> places)
    {
        Places = new List<AbstractGeneralParticipants>(places.Count);
        for (int i = 0; i < places.Count; i++)
        {
            Places.Add(new GeneralParticipants(places[i]));
        }
    }

The 2nd function looks unpleasantly, but I don't see any better way for that. And also, ReSharper suggests me to replays 'for' loop with 'foreach'...

Please advise.

Thanks a lot.

Budda
  • 18,015
  • 33
  • 124
  • 206
  • You are passing in a list to the constructor, so why "if 'Schema' constructor is called in the middle of any iteration then order of elements in 'Places' list will be shifted"? could you explain? – Mahesh Velaga Feb 04 '11 at 23:45
  • Can you please put more explanation? because the description is not enough! – Ahmed Magdy Feb 04 '11 at 23:51

3 Answers3

1

You're wrong to think that if list is being iterated in some place of program, its current position becomes shifted when it is passed as a parameter.

The list does not hold any current index or state. It's the client code that does.

What foreach essentially does is calling GetEnumerator method and uses IEnumerator to move forward and read current value. Once you pass list somewhere else, another foreach gets its own IEnumerator which starts from first element again.

Consider this sample:

void InnerEnumerate (List<int> innerList)
{
    foreach (var innerItem in innerList)
        Console.WriteLine ("- inner item {0}", innerItem);
}

var outerList = new List<int> { 1, 2, 3 };
foreach (var outerItem in outerList) {
    Console.WriteLine ("Outer item {0}", outerItem);
    InnerEnumerate (outerList); // pass list as a parameter
}

This is the output:

Outer item 1
- inner item 1
- inner item 2
- inner item 3
Outer item 2
- inner item 1
- inner item 2
- inner item 3
Outer item 3
- inner item 1
- inner item 2
- inner item 3

As you can see, foreach es are independent and don't know anything about each other. They always start from the beginning.

Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
  • "another foreach gets its own IEnumerator which starts from first element again" really? – Budda Feb 05 '11 at 01:24
  • ... Is this a foreach loop feature only? Or same can be applied for all other extension methods? – Budda Feb 05 '11 at 01:25
  • I think you need to understand how `foreach` really works. http://stackoverflow.com/questions/398982/how-do-foreach-loops-work-in-c/398996#398996 – Dan Abramov Feb 05 '11 at 01:27
  • LINQ extension methods don't modify the original collection, right. Collection can be passed around, though I don't exactly understand why you'd need to make a LINQ call inside another LINQ call. – Dan Abramov Feb 05 '11 at 01:29
  • I know how 'foreach' works, but I don't know how 'GetEnumarator' is implemented for 'List' class. – Budda Feb 17 '11 at 15:39
  • Actually, I can guess now... And in most cases it doesn't matter as we will have a separate object... I was confused with IEnumarable (that is based on 'yield' keyword...) and its possible implementation inside of collection itself... – Budda Feb 17 '11 at 16:01
  • Well, `List` is basically just a wrapper around an array. – Dan Abramov Feb 17 '11 at 16:13
0

In your second example you can use a foreach loop as Resharper suggested:

Places = new List<AbstractGeneralParticipants>(places.Count);
foreach (Place place in places)
{
    Places.Add(new GeneralParticipants(place));
}

Or you can also do it using LINQ as in your first example, which is a bit more concise.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • Data in list are not changed. The problem is that IEnumerable<> doesn't guarantee order in which items are iterated. That is important for me (in current case). And I don't see any difference between using foreach loop or 'Select' extension methods: both are IEnumerable-based. – Budda Feb 04 '11 at 23:55
  • 3
    @Budda: For `List` using the `IEnumerable` interface will return the element in the same order as directly indexing them. – Mark Byers Feb 04 '11 at 23:59
0

Guess, the best solution will be to avoid relying on the items order in the list. Instead would be better to add additional parameter into 'CountryParticipantsStages' class that will be used to determining its 'position' in list.

Budda
  • 18,015
  • 33
  • 124
  • 206