Monday 9 January 2012

Basics of anonymous Methods in C# 2.0

Anonymous method is a new language feature in C# 2.0.

Anonymous methods allow us to define a code block where a delegate object is acceptable. This facility saves us an extra step of creating a delegate for small code blocks that we want to pass to a delegate. It also removes the cluttering of small methods in the class code.

For example, that let us say we have a string collection class named MyCollection. This class has a method that retrieves all the items in the collection that satisfies a user supplied criteria, i.e., the caller decides whether a particular item in the collection qualifies for being retrieved as part of the return array from this method.


public class MyCollection
{
public delegate bool SelectItem(string sItem);

public string[] GetFilteredItemArray(SelectItem itemFilter)
{
List sList = new List();
foreach(string sItem in m_sList)
{
if (itemFilter(sItem) == true) sList.Add(sItem);
}
return sList.ToArray();
}

public List ItemList
{
get
{
return m_sList;
}
}

private List m_sList = new List();
}


We can write code as shown below to use the above defined class:


protected void Page_Load(object sender, EventArgs e)
{
MyCollection objMyCol = new MyCollection();
objMyCol.ItemList.Add("Aditya");
objMyCol.ItemList.Add("Tanu");
objMyCol.ItemList.Add("Manoj");
objMyCol.ItemList.Add("Ahan");
objMyCol.ItemList.Add("Hasi");

// get an array of string items in the collection that start

// with letter 'A'

//

string[] AStrings = objMyCol.GetFilteredItemArray(FilterStringWithA);
Console.WriteLine("----- Strings starting with letter 'A' -----");
foreach (string s in AStrings)
{
Console.WriteLine(s);
}

// get an array of string items in the collection that start

// with letter 'T'

//

string[] TStrings = objMyCol.GetFilteredItemArray(FilterStringWithT);
Console.WriteLine("----- Strings starting with letter 'T' -----");
foreach (string s in TStrings)
{
Console.WriteLine(s);
}
}

public static bool FilterStringWithA(string sItem)
{
if (sItem[0] == 'A')
return true;
else
return false;
}

public static bool FilterStringWithT(string sItem)
{
if (sItem[0] == 'T')
return true;
else
return false;
}


Here the problem is for each simple criteria we want to provide, we should define a method (static or instance). This soon clutters the class code. With anonymous methods, the code becomes much natural. Below is the re-written code using anonymous methods.


protected void Page_Load(object sender, EventArgs e)
{
MyCollection objMyCol = new MyCollection();
objMyCol.ItemList.Add("Apple");
objMyCol.ItemList.Add("Grape");
objMyCol.ItemList.Add("Orange");
objMyCol.ItemList.Add("Blackberry");
objMyCol.ItemList.Add("Blueberry");

// get an array of string items in the collection that start

// with letter 'A'

//

string[] AStrings = objMyCol.GetFilteredItemArray(delegate(string sItem)
{
if (sItem[0] == 'A')
return true;
else
return false;
});
System.Diagnostics.Debug.WriteLine("----- Strings starting with letter 'A' -----");
foreach (string s in AStrings)
{
System.Diagnostics.Debug.WriteLine(s);
}

// get an array of string items in the collection that start

// with letter 'T'

//

string[] TStrings = objMyCol.GetFilteredItemArray(delegate(string sItem)
{
if (sItem[0] == 'B')
return true;
else
return false;
});
Console.WriteLine("----- Strings starting with letter 'B' -----");
foreach (string s in TStrings)
{
System.Diagnostics.Debug.WriteLine(s);
}
}


As shown in the above sample, we were able to define the criteria with in-line code blocks instead of defining a new method to represent each criteria. Truly speaking, using such inline code may look natural and avoid defining new methods, but if this technique is used for larger inline code blocks, then the code soon becomes unmanageable and may lead to duplications. So, be selective in using methods vs. inline anonymous methods as delegates/event handlers.

Now, this is the basics of anonymous methods. The rest of the article deals with how anonymous methods work internally in different scenarios. Understanding how anonymous methods are implemented and work internally is important for their correct usage. Else, the results of your code using anonymous methods will look unpredictable.

Anonymous methods always start with a delegate keyword, followed by parameters to be used inside the method and the method body itself. As seen from the above code sample, users need not specify the return type of the anonymous method. It is inferred from the return statement within the method body. The .NET CLR cannot execute free flowing code blocks like anonymous methods. CLR requires that every method it executes is part of a type and should be a static method or instance method. So when you write anonymous methods in a class code and compile the code, the C# compiler silently creates a static or instance method within the same class where you defined the anonymous method. So anonymous methods are just a convenient syntax for defining your own methods inside the class to pass to delegates (delegate handlers/event handlers).

When you compile the above sample, the C# compiler creates two private static methods inside the class, where we defined the anonymous methods. It then replaces the anonymous methods with the address of those static methods. How the compiler decides to create static methods or instance methods depends on the usage of the static or instance data members of the class within which the anonymous methods are defined.

Click here to read more about the internal of anonymous methods.

No comments:

Post a Comment