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;
    }
    


  }
}

Monday, February 22, 2010

Delegates Inside




Delegates are one of most complex and simplest concept in .Net ;) .

Delegates in c# are defained as Function Pointers. Those functions can be an instance function or a static function. In case of instance function delegeate store the reference of that object in its property called "Target".

Once an instance function is added to a deletegate then that function will always be invoked by delegate event if you set instance to null................

Lets take an example :

using System;

static class Program
{
[STAThread]
static void Main()
{

EventHandelerClass handeler = new EventHandelerClass("My Text");
delShow showMe = new delShow(handeler.OnShow);
handeler.Text = "Changed ";
handeler = null;  // set to null 
GC.Collect(); // Make sure it is released 
Console.WriteLine(showMe(" From Delegate"));
Console.ReadLine();

}
}


public delegate String delShow(String msg);

public class EventHandelerClass
{
public String Text
{
get;
set;
}
public EventHandelerClass(string text)
{
Text = text;
}

public String OnShow(String msg)
{
return this.Text + msg;
}


}



Above program will display message "My Text From Delegate" even if handeler is set to null.

This is because when you add a instance method to a delegate it store reference of that instance in its "Target" property. When we set handeler = null actually we are saying now "handeler" will no longer point to the address but delegate "showMe" is still pointing to same address ( ref How reference types are stored ? ).

Whole idea is once we have assign a function pointer to a delegate or event it will always call it ; simply setting instance to null will not remove the handler. To remove handler we need to either use "-=" or "MulticastDelegate.Remove" method.

I faced this problem while implementing MVP in one of my project where I have disposed a consumer form but the event handler was still called. in my next article I will try to explain MVP implementation in detail.