Visual Studio 2010!

Read now >

View Now
DevSource RSS FEEDS
XML Want an easy way to keep up with breaking tech news? And the Get DevSource headlines delivered to your desktop with RSS.
ADVERTISEMENT
ADVERTISEMENT

 

DevSource.com: Your Source for Visual Studio on Facebook
ADVERTISEMENT
Programming with Generic Delegates and Lambda Expressions
By Paul Kimmel

Rate This Article: Add This Article To:

Paul Kimmel shows you how to use generic delegates in C#.

Introduction

In all likelihood many developers are going to find Lambda Expressions and Generic Delegates challenging to understand. Lambda Expressions are a very short-hand syntax for functions. Oft referred to as functional programming, and generic delegates will be challenging because they employ generics, delegates, and Lambda Expressions. Arguable these are all upper tier subjects in terms of complexity.

If a person glossed over any of these subjects—Lambda Expressions, delegates, or generics—along their learning journey then everything else will be difficult. On top of that, Lambda Expressions and generic delegates can yield some statements that are terse and difficult to decipher even if these subjects are understood. In this article, I will introduce—a little light reading for the holidays—the generic delegates Action, Predicate, and Func, demonstrating how these delegates are used and how they used in conjunction with Lambda Expressions.

Let’s start with an overview of generics, delegates, and lambda Expressions.

What are Generics?

Generics, similar to what are called templates in C++ or parameterized types in the UML, simply abstract behaviors from data. A generic method or class is defined without the author specifying the data type. The consumer—the user of the generic provides the data type. Generics eliminate the need to write a linked list implementation for example for every possible data type.

Generics can be challenging even for those pretty comfortable with them because the parameterized type can also be a delegate—a method—as well as simple data.

What are Delegates?

A delegate is the objectification of an event handler or function pointer. Delegates support event driven program where some code plays the role of initiator and some other code the responder. Producers add event properties or delegate arguments to let consumers add the behavior at the time of consumption or runtime. This supports a very dynamic model of programming.

In practice—at least for now—it would be an intractable problem to change a tire while driving the same automobile, but a software application could simulate this behavior. Software is much less limited by the physical world than anything else. (Perhaps this is also why software engineering is much more complex than many other kinds of engineering—because we aren’t constrained nearly as much by physics.)

What are Lambda Expressions?

Lambda Expressions are an evolution from functions, to delegates, to anonymous delegates, to Lambda Expressions. So Lambda Expressions are basically functions that use a very short notation. The left hand argument are the parameters followed by the => goes to operator, or lambda operator, and the function body on the right side. All of the traditional function gunk has been eliminated. Here is an example of simple Lambda Expression:

y => y + 5;

The preceding Lambda Expression is equivalent to:

int AddFive(int y)
{
    return y + 5;
}

The very short notation used for Lambda Expressions make then suitable new language features like LINQ, and they can enhance productivity because much less typing is required.

Defining Actions

Action is defined as a generic delegate in the System namespace. Action is designed to accept one argument—a parameterized type—and perform some operation on that argument. The return type is void and you supply the behavior.

The behavior can be supplied through a delegate, anonymous delegate, or Lambda Expression. The following defines an Action print where the parameterized type is a string—Action<string>--and the Lambda Expression—str => Console.WriteLine(str)—simply sends the string to the console.

The Action delegate is defined for several methods of the Array and List<T> classes. For example, we can shorten the traditional foreach, do behavior construct with Array.ForEach. Listing 1 shows how we might iterate an array of numbers now, and Listing 2 shows how we can iterate the array of numbers using Array.ForEach and an Action.

Listing 1: Iterating an array of numbers old school.

int[] numbers = new int[] { 1, 2, 3, 4, 5, 6 };
foreach (int num in numbers)
  Console.WriteLine(num);

Listing 2: Iterating an array of integers using Aray.ForEach and the generic delegate, Action.

int[] numbers = new int[] { 1, 2, 3, 4, 5, 6 };
Array.ForEach(numbers, num => Console.WriteLine(num));

The savings between these two styles are modest, but over the course of an application or a career these savings will add up. Additionally greater savings may be achieved by code generators as these smaller expressions can be generated much more simply.

Defining Predicates

Predicate is a generic delegate designed to accept a single input criteria and return a Boolean indicating if the input value meets the criteria. The criteria is a function; we’ll use a Lambda Expression to satisfy this role. In Listing 3 shows how we can use Predicate to perform a simple string-length test.

Listing 3: Using the generic delegate Predicate.

Action<string> print = str => Console.WriteLine(str);
Predicate<string> lengthTest = str => str.Length == 5;
print(lengthTest("\"Welcome to Valhalla Tower material defender!\").ToString());

Defining Func Instances

System.Func accepts n arguments. The first n-1 arguments are input parameters and the nth argument specifies the return type. Func in Listing 4 accepts two integer arguments and returns a Boolean. The Lambda Expression tests the two integers for equality, comparing the result to 0 to derive the return value.

Listing 4: the generic delegate Func with two integer inputs and a bool output.

Func<int, int, bool> areEqual = (x, y) => x.CompareTo(y) == 0;
print(areEqual(7, 8).ToString());

Summary

The generic delegates Action, Predicate, and Func are used all over the place in the new version of .NET. These delegates support extension methods and generic types like Array<T> and List<T>. You can of course use regular delegates, anonymous delegates, or Lambda Expressions with these delegates.

Biography

Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on object-oriented programming and .NET. Check out his upcoming book LINQ Unleashed for C# due in Spring 2008. You may contact him for technology questions at pkimmel@softconcepts.com.

If you are interested in joining or sponsoring a .NET Users Group, check out www.glugnet.org. Glugnet opened a users group branch in Flint, Michigan in August 2007. If you are interested in attending, check out the www.glugnet.org web site for updates.




Discuss Programming with Generic Delegates and Lambda Expressions
 
clarifying! Used it a million times but didn't know what was behind it until...
Greate articale.....it has clear myths about lemda expressions and generic...
>>> Post your comment now!
 

 
 
>>> More Microsoft Languages Articles          >>> More By Paul Kimmel