Friday, February 26, 2010

IEnumerable and LINQ inside



IEnumerable provide us an easy way to iterate through a collection but it actually does not hold that collection data by itself. It means whenever you will ask IEnumerable to get next data if will go to the source again. What if the source of IEnumerable collection is a LINQ query and content of that LINQ query keep on changes?

Yes our IEnumerable will be affected automatically. Here is one example :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
  static class Program
  {
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
      List<Person> ListOfPersons= new List<Person> {
      new Person { Salary =1000, Name ="Person1"},
      new Person { Salary =2000, Name ="Person2"}
      };
      Person Person3 = new Person { Salary =3000, Name ="Person3"};
      Person Person4 =  new Person { Salary =4000, Name ="Person4"};

      ListOfPersons.Add (Person3 );
      ListOfPersons.Add(Person4); 

      IEnumerable<Person> BadSalaryList = from person in ListOfPersons
                                           where person.Salary < 2500
                                           select person;

      // Now above LINQ will be Executed 
      Console.WriteLine(BadSalaryList.Count()); // output 2 

      //Lets change Person3 
      // This will re execute the query 
      Person3.Salary = 500; // This person will be automatically  included in BadSalaryList        


      Console.WriteLine(BadSalaryList.Count()); // output 3 Person3 Added in last 

      // Lets change salary of Person1    
      // This will re execute the query 
      ListOfPersons[0].Salary = 7000; 


      Console.WriteLine(BadSalaryList.Count()); // output 3 Person3 Added in last 
      
  //    Console.WriteLine(BadSalaryList.Count());
      Console.ReadLine();

    }
  }

  public class Person
  {
    public int Salary
    {
      get;
      set;
    }
    public String Name
    {
      get;
      set;
    }
    


  }
}



If we notice whenever we change the data of Person object IEnumerable collection tries to reevaluate LINQ based on new collection. We need to be very careful about this as IEnumerable collection is not fixed
1) It will be changed based on LINQ conditions
2) We might need to see performance as it will re evaluate the query on each change.

This feature is useful when you want to display list of Error objects to user and providing user a functionality to correct the error. In that case the collection will be automatically managed.

If we do not want collection to be modified then we can store output in List<> . Here is the example :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
  static class Program
  {
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
      List<Person> ListOfPersons= new List<Person> {
      new Person { Salary =1000, Name ="Person1"},
      new Person { Salary =2000, Name ="Person2"}
      };
      Person Person3 = new Person { Salary =3000, Name ="Person3"};
      Person Person4 =  new Person { Salary =4000, Name ="Person4"};

      ListOfPersons.Add (Person3 );
      ListOfPersons.Add(Person4); 

      List <Person> BadSalaryList = (from person in ListOfPersons
                                           where person.Salary < 2500
                                           select person).ToList ();

      // Now above LINQ will be Executed 
      // Only once 
      Console.WriteLine(BadSalaryList.Count()); // output 2 

      //Lets change Person3       
      //Query will not be executed 
      Person3.Salary = 500; 
      Console.WriteLine(BadSalaryList.Count()); // output 2

      // Lets change salary of Person1    
      //Query will not be executed 
      ListOfPersons[0].Salary = 7000;

      Console.WriteLine(BadSalaryList.Count()); // output 2 
      
  //    Console.WriteLine(BadSalaryList.Count());
      Console.ReadLine();

    }
  }

  public class Person
  {
    public int Salary
    {
      get;
      set;
    }
    public String Name
    {
      get;
      set;
    }
    


  }
}

1 comment:

Anonymous said...

It's really very nice and helpful article.