user7354346
user7354346

Reputation:

Using IEnumerator to iterate through a list

Let's say I have a list of employee instances, employeeList. I can iterate through them, like this:

IEnumerator enumerator = employeeList.GetEnumerator();
while (enumerator.MoveNext())
{
    Console.Write(enumerator.Current + " ");
}

I have three questions:

  1. I have a general idea about how enumerators work, just like iterators in C++. But I don't understand the MoveNext() method (like itr ++ in C++), because the method first checks the condition (whether it is in the last element). Let's say we use enumerator.Current to access the first element: I think it actually has already "moved" to the next element in the list, as MoveNext() has been called. So shouldn't the object that Current points to actually be the second element in the list?

  2. I think it would make sense that we can access the current element when using enumerator.Current. For example, we should be able to use enumerator.Current.name, just like we can use (*itr).name or itr=>name in C++. However, C# looks like it doesn't implement this kind of functionality. So what's the point of using enumerator.Current?

  3. This question is not related to IEnumerator. I just saw some code like this:
    IEnumerable<int> result = GetData() ?? Enumerable.Empty<int>;
    As a beginner in C#, I only know the && and || operators. What is ???

Upvotes: 26

Views: 45730

Answers (4)

Maksim Simkin
Maksim Simkin

Reputation: 9679

Use IEnumerable just this way:

foreach (var e in employeeList)
{
  Console.Write(e + " ");
}

Upvotes: 3

Tim Schmelter
Tim Schmelter

Reputation: 460228

Read documentation: "After an enumerator is created, the enumerator is positioned before the first element in the collection, and the first call to MoveNext advances the enumerator to the first element of the collection"

The problem with your code is that you assign the enumerator to a non-generic enumerator variable. That works because the generic IEnumerator<T> interface inherits from the non-generic. But that's also the reason why you can't use properties of the Employee-class since the type is Object. You have to cast enumerator.Current to the correct type first.

Therefore it's better to use the generic version (and dipose it properly with using):

using(IEnumerator<Employee> empEnumerator = employeeList.GetEnumerator())
{
    while(empEnumerator.MoveNext())
    {
        // now empEnumerator.Current is the Employee instance without casting
        Employee emp = empEnumerator.Current;
        string empName = emp.Name;  // ...
    }
}

You can also use var which works like a placeholder for the real type in C#:

using(var empEnumerator = employeeList.GetEnumerator())
{ ... }

If all you need is to enumerate the whole collection a foreach is more comfortable:

foreach(Employee emp in employeeList)
{
     Console.WriteLine(emp.Name);
}

Upvotes: 42

HaBo
HaBo

Reputation: 14297

IEnumerable Interface

Exposes an enumerator, which supports a simple iteration over a non-generic collection.

foreach (var employee in employeeList)
{
    // do your stuff  here, you have full employee object
   Console.WriteLine(employee.FirstName); 
}

c# null coalescing operator

The ?? operator is called the null-coalescing operator. It returns the left-hand operand if the operand is not null; otherwise it returns the right hand operand.

Upvotes: 1

Heinzi
Heinzi

Reputation: 172390

  1. Initially, the enumerator is positioned before the first element (since an enumerable might be empty). Thus, the first invocation of MoveNext moves it to the first element (or returns false, if the enumerable is empty).

  2. You are using the old, non-generic version of IEnumerator, where Current returns an object. You can cast the object to the concrete type and invoke .name, or, even better, use a type for employeeList which returns a strongly typed IEnumerator<Employee> (such as List<Employee>).

  3. This is the null-coalescing operator.

PS: In the future, please create one SO question per question. 1+2 can be seen as related, but 3 definitely isn't.

PPS: If you just want a space-separated list of employee names, you don't need an explicit loop at all:

var names = String.Join(" ", employeeList.Select(e => e.name));

Upvotes: 5

Related Questions