Tutorial :How does linq Last() work?



Question:

I dont understand how current can be null and last can be an object while last being a LINQ function. I thought last uses GetEnumerator and keeps going until current == null and returns the object. However as you can see the first GetEnumerator().Current is null and last somehow returns an object.

How do linq Last() work?

var.GetEnumerator().Current  var.Last()  


Solution:1

From using Reflector on System.Core.dll:

public static TSource Last<TSource>(this IEnumerable<TSource> source)  {      if (source == null)      {          throw Error.ArgumentNull("source");      }      IList<TSource> list = source as IList<TSource>;      if (list != null)      {          int count = list.Count;          if (count > 0)          {              return list[count - 1];          }      }      else      {          using (IEnumerator<TSource> enumerator = source.GetEnumerator())          {              if (enumerator.MoveNext())              {                  TSource current;                  do                  {                      current = enumerator.Current;                  }                  while (enumerator.MoveNext());                  return current;              }          }      }      throw Error.NoElements();  }  


Solution:2

Last() will call GetEnumerator(), then keep calling MoveNext() / Current until MoveNext() returns false, at which point it returns the last value of Current retrieved. Nullity is not used as a terminator in sequences, generally.

So the implementation might be something like this:

public static T Last<T>(this IEnumerable<T> source)  {      if (source == null)      {          throw new ArgumentNullException("source");      }      using (IEnumerator<T> iterator = source.GetEnumerator())      {          if (!iterator.MoveNext())          {              throw new InvalidOperationException("Empty sequence");          }          T value = iterator.Current;          while (iterator.MoveNext())          {              value = iterator.Current;          }          return value;      }  }  

(This could be implemented with a foreach loop, but the above shows the interaction more explicitly. This also ignores the possibility of accessing the last element directly.)


Solution:3

The very first value of an enumerator, before any MoveNext(), is, in the case of an array, the item at index -1.
You have to do MoveNext once to enter the actual collection.
This is done so that the constructor of the enumerator doesn't do much work, and so that these constructs are valid:

while (enumerator.MoveNext()) {        // Do Stuff   }    if(enumerator.MoveNext()) {        // Do Stuff   } // This is identical to Linq's .Any(), essentially.  


Solution:4

Remember that calling GetEnumerator doesn't typically/necessarily return the same Enumerator each time. Also, since thing.GetEnumerator() returns a new Enumerator which will start uninitialized (you haven't called MoveNext() yet), thing.GetEnumerator().Current will always be null by definition.

(I think...)


Solution:5

If you take a look at IEnumerator Interface into the Remarks section, they will state the following:

Initially, the enumerator is positioned before the first element in the collection. At this position, Current is undefined. Therefore, you must call MoveNext to advance the enumerator to the first element of the collection before reading the value of Current.

So you have to call MoveNext() once to get the first item. Otherwise you'll get just nothing.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »