Update: The javascript on this blog has been suppressed by the blogger's parser. Consequently, some of the functionality may not work. Inconvenience is regretted.

Wednesday, March 10, 2010

Leveraging new delegates in C# 3.0

I interview a lot of developers and when I ask them about delegates there is this one answer everybody seems to know – “delegates are nothing but function pointers”. Well…my friend, you will be trying hard in the next five minutes to actually point to functions, I think to myself and fire another question – “if I give you a function, can you write me a delegate that can call the function?” and there you see myriads of delegate usages some of which can even stump the mighty compiler smile_regular. Very few can do it right. If you are getting an unusually uncomfortable feeling, it’s time to revisit this old friend smile_regular.

Assuming the reader is familiar with fundamental delegate concepts, let me introduce two extremely helpful delegates in the BCL - Action & Func . They have been used heavily in the BCL and as of .Net 4.0 each can represent functions taking up to 16 parameters (1, 2). Let’s look at the usage of each.

Func: Let’s see how Where extension method is defined on the IEnumerable class

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, Boolean> predicate)
{
foreach (TSource element in source)
{
if (predicate(element))
yield return element;
}
}

The above says you can pass your own method which returns true/false based on your logic to the Where method on any class that implements IEnumerable and you will get a filtered collection back. Sample usage: we have a list of names and we want to get names starting with character ‘a’

List<string> names = new List<string> { "Amit", "Raghu", "Piyush", "Ashok" };

Our helper method would look like:

public static bool StartsWithA(string name) 
{
return name.ToLower().StartsWith("a");
}

Here is how we could achieve the result:

var namesStartingWithA = names.Where(StartsWithA);

The above could be done more elegantly with the lambda expression as:

var namesStartingWithA = names.Where(name => name.ToLower().StartsWith("a"));

Action: I’ve long stopped writing foreach loops on collections whenever I want to get a new set of elements from the collection with some action being performed on each element. I use the ForEach extension method now, which is defined as below:

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (T element in source)
action(element);
}

The above basically performs an Action (supplied by the developer) on each element of a collection. Here is how we can use this in the above example for names:

List<string> namesAppendedWithZ = new List<string>(); 
names.ForEach(name => namesAppendedWithZ.Add(string.Format("{0}z", name)));

Lambda expression syntax is used for brevity. We can have a helper method as well to do the same job.


Using Action delegate with events

If you are fond of event based programming like me (observer is my favorite pattern), Action delegate can save you a lot of key strokes. Let’s consider a scenario in which we have a user control on which we can enter Employee information and create a new employee in database. We want to expose an event that can be raised on Employee successful creation and an entity (separate from the user control, e.g. the container form) interested can subscribe to the event and have access to the newly created Employee info. Below is how we can define the event leveraging the Action delegate:

public event Action<Employee> employeeCreatedEvent;

If we are to do this in the traditional sense, we will have to define the event like this:

public event EventHandler<EmployeeEventArgs> employeeCreatedEvent;

With an extra overhead of creating a new EventArgs derived class (data carrier) as below:

public class EmployeeEventArgs : EventArgs 
{
public Employee EmployeeInfo { get; set; }
}

I’m a lazy programmer and Action delegate is a god send for guys like me smile_regular. Here is how the event can be raised from the user control:

private void Create()
{
//Read info from UI and fill employee dto
Employee emp = new Employee {ID=null, Name=??};
db.CreateEmployee(emp);
if(employeeCreatedEvent != null)
employeeCreatedEvent(emp);
}

And here is how it can be subscribed to on the interested component:

ucEmployee.employeeCreatedEvent += new Action<Employee>(ucEmployee_employeeCreatedEvent);

That’s all, hope this is useful.

Happy Programming!!

- Pushp

4 comments:

Anonymous said...

Sorry for my bad english. Thank you so much for your good post. Your post helped me in my college assignment, If you can provide me more details please email me.

Rohit Sakalle said...

Thanks Pushp for letting me know about that Egregious....word use...very late but atleast I know...now.. :-). You posted comment long back..on my blog.

Anonymous said...

Nice fill someone in on and this enter helped me alot in my college assignement. Thanks you seeking your information.

Anonymous said...

Hi tasting this blog was very stunning , reviews like this dignify whoever visits this topic:)