Click here to Skip to main content
Click here to Skip to main content

Delegates 101 - Part III: Generic Delegates

By , 15 Jun 2011
Rate this:
Please Sign up or sign in to vote.

Introduction

In Part II, we looked at how we can use anonymous methods and lambdas to pass in-line method implementations to a method which takes a delegate as a parameter.

In this article, we will look at how we can leverage the power of generics in order to make our delegates more ...well ...generic!

Generic Delegates

Continuing with our math theme, let's look again at our original MathFunction delegate:

// C#
delegate int MathFunction(int int1, int int2);
' Visual Basic
Delegate Function MathFunction(ByVal int1 As Integer, _
                  ByVal int2 As Integer) As Integer

Well that is fine, providing all we ever want to work with are integers! In the real world, however, we are probably going to want to perform mathematical operations on all sorts of different data types. By using a generic delegate, we can have a single delegate which will handle any data type we like in a type-safe manner:

// C#
delegate TResult MathFunction<T1, T2, TResult>(T1 var1, T2 var2);
' Visual Basic
Delegate Function MathFunction(Of T1, T2, TResult)(_
         ByVal var1 As T1, ByVal var2 As T2) As TResult

Our delegate will now accept parameters of any arbitrary type and return a result of any arbitrary type.

Next, we need to modify our PrintResult() method accordingly to handle our new delegate:

// C#
static void PrintResult<T1, T2, TResult>(MathFunction<T1, T2, 
            TResult> mathFunction, T1 var1, T2 var2)
{
    TResult result = mathFunction(var1, var2);
    Console.WriteLine(String.Format("Result is {0}", result));
}
' Visual Basic
Sub PrintResult(Of T1, T2, TResult)(ByVal mathFunction As _
         MathFunction(Of T1, T2, TResult), ByVal var1 As T1, ByVal var2 As T2)
    Dim result As TResult = mathFunction(var1, var2)
    Console.WriteLine(String.Format("Result is {0}", result))
End Sub

Our simple calculator should now be able to perform mathematical operations on any data type of our choosing. Here are some examples:

// C#
PrintResult((x, y) => x / y, 5, 2); // Integer division - Result: 2
PrintResult((x, y) => x / y, 5, 2.0); // Real division - Result: 2.5
// Circumference of a circle - Result: 157.07963267949
PrintResult((x, y) => 2 * y * x, 25, Math.PI);
// Area of circle - Result: 1963.49540849362
PrintResult((x, y) => y * Math.Pow(x, 2), 25, Math.PI);
PrintResult((x, y) => (x - y).TotalDays, 
            DateTime.Now, new DateTime(1940, 10, 9));
// Days since birth of John Lennon - Result: 25775.8028079865
' Visual Basic
PrintResult(Function(x, y) CInt(x / y), 5, 2) ' Integer division - Result: 2
PrintResult(Function(x, y) x / y, 5, 2.0) ' Real division - Result: 2.5
' Circumference of a circle - Result: 157.07963267949
PrintResult(Function(x, y) 2 * y * x, 25, Math.PI)
' Area of circle - Result: 1963.49540849362
PrintResult(Function(x, y) y * Math.Pow(x, 2), 25, Math.PI)
PrintResult(Function(x, y) (x - y).TotalDays, _
            DateTime.Now, New DateTime(1940, 10, 9))
' Days since birth of John Lennon - Result: 25775.8028079865

In each example, note how the types of x and y, as well as the return type of the lambda expression, are inferred by the compiler.

Delegate Re-use

Our MathFunction generic delegate can now be used as a type for any method that accepts two parameters of any type and returns a value of any type. As such, our delegate is highly re-usable and not just restricted to our simple calculator scenario.

Indeed, Microsoft has included a whole stack of generic Func and Action delegates in the System namespace which would probably cover most conceivable scenarios. As such, we could have used one of those in our example here; however that would have defeated the object of the exercise. I personally believe there is still a strong case for creating your own delegates in certain scenarios, as it often improves code readability.

Summary

Using Generics allows us to write more versatile delegates which can be re-used for a whole variety of different scenarios. Even when using generic delegates, the compiler is still able to infer the type of any parameter and the return type.

Next: Event Handling.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

MBigglesworth79
Web Developer
United Kingdom United Kingdom
No Biography provided
Follow on   Twitter

Comments and Discussions

 
GeneralMy Vote of 5 PinmemberLaz Hack Fauker8-Nov-12 4:44 
GeneralMy vote of 3 PinmemberDebashish@CodeProject30-Nov-11 18:39 
GeneralMy vote of 5 PinmemberRhuros15-Jun-11 21:51 
GeneralMy vote of 4 PinmemberAntónio Barroso10-May-11 5:52 
GeneralMy vote of 5 Pinmembero1010wanabe9-May-11 12:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140421.2 | Last Updated 16 Jun 2011
Article Copyright 2011 by MBigglesworth79
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid