Search

Showing posts with label delegates. Show all posts
Showing posts with label delegates. Show all posts

Friday, 6 May 2011

Delegates 101 - Part IV: Event Handling


Introduction

So, here we are at the final part of this series on delegates; and it wouldn't be complete without looking at one of the key uses of delegates in .NET: Event handling.

A Simple Timer

In this article, we are going to look at a simple timer example. This timer raises two events: one when the timer is started and another when the timer has elapsed. The complete code for the timer is as follows:

// C#
public delegate void TimerEventHandler(object sender, EventArgs eventArgs);

public class SimpleTimer
{
    private TimeSpan time;

    public event TimerEventHandler Started;
    public event TimerEventHandler Elapsed;

    public SimpleTimer(long milliseconds)
        : this(TimeSpan.FromMilliseconds(milliseconds))
    {
    }

    public SimpleTimer(TimeSpan time)
    {
        this.time = time;
    }

    public void Start()
    {
        Thread timerThread = new Thread
        (
            delegate()
            {
                OnStarted(new EventArgs());
                Thread.Sleep(time);
                OnElapsed(new EventArgs());
            }
        );
        timerThread.Start();
    }

    private void OnStarted(EventArgs eventArgs)
    {
        if (Started != null)
            Started(this, eventArgs);
    }

    private void OnElapsed(EventArgs eventArgs)
    {
        if (Elapsed != null)
            Elapsed(this, eventArgs);
    }
}
' Visual Basic
Public Delegate Sub TimerEventHandler(ByVal sender As Object, ByVal eventArgs As EventArgs)

Public Class SimpleTimer

    Private _time As TimeSpan

    Public Event Started As TimerEventHandler
    Public Event Elapsed As TimerEventHandler

    Public Sub New(ByVal milliseconds As Long)
        Me.New(TimeSpan.FromMilliseconds(milliseconds))
    End Sub

    Public Sub New(ByVal time As TimeSpan)
        _time = time
    End Sub

    Public Sub Start()
        Dim timerThread As Thread = New Thread _
        ( _
            Sub()
                OnStarted(New EventArgs())
                Thread.Sleep(_time)
                OnElapsed(New EventArgs())
            End Sub _
        )
        timerThread.Start()
    End Sub

    Private Sub OnStarted(ByVal eventArgs As EventArgs)
        RaiseEvent Started(Me, New EventArgs())
    End Sub

    Private Sub OnElapsed(ByVal eventArgs As EventArgs)
        RaiseEvent Elapsed(Me, New EventArgs())
    End Sub
End Class

Now let's look at this code a little more closely. Firstly, notice how we declare a delegate for any methods which can be used to handle our two events:

// C#
public delegate void TimerEventHandler(object sender, EventArgs eventArgs);
' Visual Basic
Public Delegate Sub TimerEventHandler(ByVal sender As Object, ByVal eventArgs As EventArgs)

By convention, event handlers accept two parameters:

ParameterDescription
senderThe object which raised the event.
eventArgsAn object of type EventArgs, or inherits from EventArgs, which contains encapsulates any optional data we wish to pass to our event handler

We also declare the two events which out timer is going to raise:

// C#
public event TimerEventHandler Started;
public event TimerEventHandler Elapsed;
' Visual Basic
Public Event Started As TimerEventHandler
Public Event Elapsed As TimerEventHandler

Notice how the type of each of these events is that of the delegate which is going to handle them, in this case TimerEventHandler.

We also have convenience methods for raising each of the events:

// C#
private void OnStarted(EventArgs eventArgs)
{
    if (Started != null)
        Started(this, eventArgs);
}

private void OnElapsed(EventArgs eventArgs)
{
    if (Elapsed != null)
        Elapsed(this, eventArgs);
}
' Visual Basic
Private Sub OnStarted(ByVal eventArgs As EventArgs)
    RaiseEvent Started(Me, New EventArgs())
End Sub

Private Sub OnElapsed(ByVal eventArgs As EventArgs)
    RaiseEvent Elapsed(Me, New EventArgs())
End Sub

Note how we fire the event in exactly the same way as we would call any other delegate. Additionally, in C#, we do a check to see if any handlers have been wired-up up to our event; as firing an event without any handlers will cause an exception to be thrown.

Finally, the code which actually runs our timer and raises the events. Note how the timer is executed in a separate thread and (simply because it is in-keeping with the theme of this series) is passed to the thread as an anonymous method:

// C#
public void Start()
{
    Thread timerThread = new Thread
    (
        delegate()
        {
            OnStarted(new EventArgs());
            Thread.Sleep(time);
            OnElapsed(new EventArgs());
        }
    );
    timerThread.Start();
}
' Visual Basic
Public Sub Start()
    Dim timerThread As Thread = New Thread _
    ( _
        Sub()
            OnStarted(New EventArgs())
            Thread.Sleep(_time)
            OnElapsed(New EventArgs())
        End Sub _
    )
    timerThread.Start()
End Sub

Using our Timer

The following code shows how to use our simple timer and hook up our own methods to handle the events it raises:

// C#
static void Main(string[] args)
{
    SimpleTimer timer = new SimpleTimer(5000);
    timer.Started += timer_Started;
    timer.Elapsed += timer_Elapsed;
    timer.Start();
    Console.Read();
}

static void timer_Started(object sender, EventArgs e)
{
    Console.WriteLine("Timer has started.");
}

static void timer_Elapsed(object sender, EventArgs e)
{
    Console.WriteLine("Timer has elapsed.");
}
' Visual Basic
Sub Main(ByVal args() As String)
    Dim timer As SimpleTimer = New SimpleTimer(5000)
    AddHandler timer.Started, AddressOf timer_Started
    AddHandler timer.Elapsed, AddressOf timer_Elapsed
    timer.Start()
    Console.Read()
End Sub

Private Sub timer_Started(sender As Object, eventArgs As EventArgs)
    Console.WriteLine("Timer has started.")
End Sub

Private Sub timer_Elapsed(sender As Object, eventArgs As EventArgs)
    Console.WriteLine("Timer has elapsed.")
End Sub

Note how the syntax for wiring up our event handlers to the events is slightly different from what we've seen previously. This is because events are a type of multicast delegate, and as such multiple handlers can be wired up the same event.

Summary

Handling of events is one of the key uses for delegates in .NET. All event handlers follow a specific convention in terms of their signature and multiple different handlers can be wired up to the same event.

Thursday, 5 May 2011

Delegates 101 - Part III: Generic Delegates


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 maths 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 use of 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
PrintResult((x, y) => 2 * y * x, 25, Math.PI); // Circumference of a circle - Result: 157.07963267949
PrintResult((x, y) => y * Math.Pow(x, 2), 25, Math.PI); // Area of circle - Result: 1963.49540849362
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
PrintResult(Function(x, y) 2 * y * x, 25, Math.PI) ' Circumference of a circle - Result: 157.07963267949
PrintResult(Function(x, y) y * Math.Pow(x, 2), 25, Math.PI) ' Area of circle - Result: 1963.49540849362
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 have 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 types of any parameters and the return type.

Next: Event Handling

Wednesday, 4 May 2011

Delegates 101 - Part II: Anonymous Methods and Lambdas


Introduction

In Part I of this series, we looked at what .NET delegates are, and how they can be used to hold methods in variables, or to pass methods as parameters into other methods.

In this article, we are going to look at how we can use anonymous methods and lambdas, to make our code more terse by reducing the amount of code we need to write.

Anonymous Methods

Firstly, here is a recap of our SimpleCalc.exe code from Part I:

// C#
delegate int MathFunction(int int1, int int2);

static int Add(int int1, int int2)
{
    return int1 + int2;
}

static int Subtract(int int1, int int2)
{
    return int1 - int2;
}

static int Multiply(int int1, int int2)
{
    return int1 * int2;
}

static int Divide(int int1, int int2)
{
    return int1 / int2;
}

static void PrintResult(MathFunction mathFunction, int int1, int int2)
{
    int result = mathFunction(int1, int2);
    Console.WriteLine(String.Format("Result is {0}", result));
}

static void Main(string[] args)
{
    int left = int.Parse(args[0]);
    char theOperator = args[1][0];
    int right = int.Parse(args[2]);
    MathFunction mathFunction;
    if (theOperator == '+')
        mathFunction = Add;
    else if (theOperator == '-')
        mathFunction = Subtract;
    else if (theOperator == '*')
        mathFunction = Multiply;
    else
        mathFunction = Divide;
    PrintResult(mathFunction, left, right);
}
' Visual Basic
Delegate Function MathFunction(ByVal int1 As Integer, ByVal int2 As Integer) As Integer

Function Add(ByVal int1 As Integer, ByVal int2 As Integer) As Integer
    Return int1 + int2
End Function

Function Subtract(ByVal int1 As Integer, ByVal int2 As Integer) As Integer
    Return int1 - int2
End Function

Function Multiply(ByVal int1 As Integer, ByVal int2 As Integer) As Integer
    Return int1 * int2
End Function

Function Divide(ByVal int1 As Integer, ByVal int2 As Integer) As Integer
    Return CInt(int1 / int2)
End Function

Sub PrintResult(ByVal mathFunction As MathFunction, ByVal int1 As Integer, ByVal int2 As Integer)
    Dim result As Integer = mathFunction(int1, int2)
    Console.WriteLine(String.Format("Result is {0}", result))
End Sub

Sub Main(ByVal args() As String)
    Dim left As Integer = Integer.Parse(args(0))
    Dim theOperator As Char = args(1)(0)
    Dim right As Integer = Integer.Parse(args(2))
    Dim mathFunction As MathFunction
    If theOperator = "+" Then
        mathFunction = AddressOf Add
    ElseIf theOperator = "-" Then
        mathFunction = AddressOf Subtract
    ElseIf theOperator = "*" Then
        mathFunction = AddressOf Multiply
    Else
        mathFunction = AddressOf Divide
    End If
    PrintResult(mathFunction, left, right)
End Sub

As you can see, each method that we want to assign to a variable of type MathFunction has been declared as a specific, named method (e.g.: Add(), Subtract() etc.). Now, it would be good if we could specify our MathFunction methods anonymously and in-line as we pass them into our PrintResult() method.

Well, this we can do as follows:

// C#
static void Main(string[] args)
{
    int left = int.Parse(args[0]);
    char theOperator = args[1][0];
    int right = int.Parse(args[2]);
    if (theOperator == '+')
        PrintResult(delegate(int int1, int int2) { return int1 + int2; }, left, right);
    else if (theOperator == '-')
        PrintResult(delegate(int int1, int int2) { return int1 - int2; }, left, right);
    else if (theOperator == '*')
        PrintResult(delegate(int int1, int int2) { return int1 * int2; }, left, right);
    else
        PrintResult(delegate(int int1, int int2) { return int1 / int2; }, left, right);
}

Note how the parameters required by our anonymous methods are enclosed between the parentheses; and the main body of our methods are enclosed in curly braces. This removes the need to have named methods for each of our mathematical functions, considerably reducing the number of lines of code.

If you are wondering why there is no Visual Basic example, it is because Visual Basic currently does not support anonymous methods. It does, however, support the use of Lambdas.

Lambdas

A statement lambda is, to all intents and purposes, simply a shorthand way of writing an anonymous method. We can thus shorten our code further by changing our anonymous methods into statement lambdas, as follows:

// C#
static void Main(string[] args)
{
    int left = int.Parse(args[0]);
    char theOperator = args[1][0];
    int right = int.Parse(args[2]);
    if (theOperator == '+')
        PrintResult((int1, int2) => { return int1 + int2; }, left, right);
    else if (theOperator == '-')
        PrintResult((int1, int2) => { return int1 - int2; }, left, right);
    else if (theOperator == '*')
        PrintResult((int1, int2) => { return int1 * int2; }, left, right);
    else
        PrintResult((int1, int2) => { return int1 / int2; }, left, right);
}
' Visual Basic
Sub Main(ByVal args() As String)
    Dim left As Integer = Integer.Parse(args(0))
    Dim theOperator As Char = args(1)(0)
    Dim right As Integer = Integer.Parse(args(2))
    If theOperator = "+" Then
        PrintResult(Function(int1, int2)
                        Return int1 + int2
                    End Function, left, right)
    ElseIf theOperator = "-" Then
        PrintResult(Function(int1, int2)
                        Return int1 - int2
                    End Function, left, right)
    ElseIf theOperator = "*" Then
        PrintResult(Function(int1, int2)
                        Return int1 * int2
                    End Function, left, right)
    Else
        PrintResult(Function(int1, int2)
                        Return CInt(int1 / int2)
                    End Function, left, right)
    End If
End Sub

Note how the types of our int1 and int2 parameters are now automatically inferred by the compiler.

We can now reduce our code even further by using expression lambdas instead of statement lambdas. Expression lambdas are single-line lambdas which implicitly return a value. In our example, they would look as follows:

// C#
static void Main(string[] args)
{
    int left = int.Parse(args[0]);
    char theOperator = args[1][0];
    int right = int.Parse(args[2]);
    if (theOperator == '+')
        PrintResult((int1, int2) => int1 + int2, left, right);
    else if (theOperator == '-')
        PrintResult((int1, int2) => int1 - int2, left, right);
    else if (theOperator == '*')
        PrintResult((int1, int2) => int1 * int2, left, right);
    else
        PrintResult((int1, int2) => int1 / int2, left, right);
}
' Visual Basic
Sub Main(ByVal args() As String)
    Dim left As Integer = Integer.Parse(args(0))
    Dim theOperator As Char = args(1)(0)
    Dim right As Integer = Integer.Parse(args(2))
    If theOperator = "+" Then
        PrintResult(Function(int1, int2) int1 + int2, left, right)
    ElseIf theOperator = "-" Then
        PrintResult(Function(int1, int2) int1 - int2, left, right)
    ElseIf theOperator = "*" Then
        PrintResult(Function(int1, int2) int1 * int2, left, right)
    Else
        PrintResult(Function(int1, int2) CInt(int1 / int2), left, right)
    End If
End Sub

Note how the body of the lambda is no longer enclosed within an explicit code block; and that the the explicit return statement has been removed.

Summary

Anonymous methods (C# only) and lambdas (C# and VB.NET) allow us to write much more concise code by removing the need to declare and name each method specifically.

Next: Generic Delegates

Tuesday, 3 May 2011

Delegates 101 - Part I: What is a Delegate?


Introduction

OK, so what has prompted me to start writing a basic tutorial series; and why on delegates? Well, the answer is quite simple: I have found few (if any) articles on the Web which actually do a good job of explaining what delegates are in .NET and how they can be used. Nearly every article I have read (and there have been a few) go into great depths about event-handling and how delegates are used in that scenario; whilst neglecting to cover the basics. Important though it is, event handling is not a delegate's raison d'ĂȘtre.

It's little wonder, therefore, that I have seen many a trainee/junior developer (myself included, back in the day...) scratching their heads and looking somewhat befuddled when trying to get their minds round concepts such as passing methods as parameters, and lambda expressions.

As a result, this article will specifically not cover event handling but instead will be, for the moment, sticking with the basics of .NET delegates

An Example in JavaScript

I'm going to start with an example in JavaScript, in the hope that it will make explanations easier when we move onto a .NET example.

The following is a simple calculator. The user selects and operator from the drop-down and inputs an integer in either side. When the user clicks the 'Calculate' button, the result of the simple sum is output on the page. Here is the HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Simple Calculator</title>
    <script src="../Scripts/jquery-1.5.1.min.js" type="text/javascript"></script>
    <script src="../Scripts/SimpleCalc.js" type="text/javascript"></script>
</head>
<body>
    <h1>
        Simple Calculator</h1>
    <div>
        <input id="intLeft" type="text" style="width: 50px;" />&nbsp;
        <select id="operator">
            <option value="+">Add</option>
            <option value="-">Subtract</option>
            <option value="*">Multiply By</option>
            <option value="/">Divide By</option>
        </select>&nbsp;
        <input id="intRight" type="text" style="width: 50px;" />&nbsp;
        <input id="calculate" type="button" value="Calculate" />
    </div>
    <hr />
    <div>
        <label for="result">
            Result:</label><input id="result" type="text" style="width: 150px;" disabled="disabled" />
    </div>
</body>
</html>

And the JavaScript which performs the calculation is broken down as follows. Firstly we have four functions which perform each type of mathematical operation:

function add(int1, int2) {
    return int1 + int2;
}

function subtract(int1, int2) {
    return int1 - int2;
}

function multiply(int1, int2) {
    return int1 * int2;
}

function divide(int1, int2) {
    return int1 / int2;
}

OK, nothing magical there. What is more interesting is what we do when the 'Calculate' button is clicked:

$(document).ready(function () {
    $("#calculate").click(function () {
        var left = parseInt($("#intLeft").val())
        var right = parseInt($("#intRight").val());
        var operator = $("#operator").val();
        var mathFunc;
        if (operator === '+')
            mathFunc = add;
        else if (operator === '-')
            mathFunc = subtract;
        else if (operator === '*')
            mathFunc = multiply;
        else
            mathFunc = divide;
        printResult(mathFunc, left, right);
    });
});

As you can see, we first parse the two integers from the textboxes and get the chosen operator from the drop-down. Next we declare the variable mathFunc. Now since JavaScript is a weakly-typed language we can assign just about anything we like to a variable, including functions. We then perform some simple logic to assign the appropriate function to the variable. Note the lack of parentheses ('(' and ')') when assigning the function. This is how we assign the function itself to the variable instead of the result of calling it.

Next we call the printResult() function, passing in our mathFunc variable as well as the two integers:

function printResult(mathFunc, int1, int2) {
    var result = mathFunc(int1, int2);
    $("#result").val(result);
}

This function calls the function we have passed to it, and outputs the result to the page.

Now for some .NET

Now we can do exactly the same thing in .NET and for this illustration I am going to use a console application which takes the two integers and the operator as arguments (e.g.: SimpleCalc.exe 10 + 7)

Again we have our basic mathematical functions:

// C#
static int Add(int int1, int int2)
{
    return int1 + int2;
}

static int Subtract(int int1, int int2)
{
    return int1 - int2;
}

static int Multiply(int int1, int int2)
{
    return int1 * int2;
}

static int Divide(int int1, int int2)
{
    return int1 / int2;
}
' Visual Basic
Function Add(ByVal int1 As Integer, ByVal int2 As Integer) As Integer
    Return int1 + int2
End Function

Function Subtract(ByVal int1 As Integer, ByVal int2 As Integer) As Integer
    Return int1 - int2
End Function

Function Multiply(ByVal int1 As Integer, ByVal int2 As Integer) As Integer
    Return int1 * int2
End Function

Function Divide(ByVal int1 As Integer, ByVal int2 As Integer) As Integer
    Return CInt(int1 / int2)
End Function

But in a strongly-typed environment, such as .NET, how do we assign a method to a variable? What should the type of such a variable be? Well, this is where delegates come in. Essentially a delegate can be thought of as another custom type which specifies the signature of a method which can be assigned to variables of that type. We declare our delegate as follows:

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

As you can see, the signature of the delegate matches the signatures of our four functions. We are saying that any variable of type MathFunction can only be assigned a method which takes two integers as parameters and returns an integer.

Now if we look at our PrintResult() method:

// C#
static void PrintResult(MathFunction mathFunction, int int1, int int2)
{
    int result = mathFunction(int1, int2);
    Console.WriteLine(String.Format("Result is {0}", result));
}
' Visual Basic
Sub PrintResult(ByVal mathFunction As MathFunction, ByVal int1 As Integer, ByVal int2 As Integer)
    Dim result As Integer = mathFunction(int1, int2)
    Console.WriteLine(String.Format("Result is {0}", result))
End Sub

Here we see the mathFunction parameter is of type MathFunction and so accepts one of our functions. As with the JavaScript example, the method calls the function passed to it and outputs the result.

Finally, the Main() method of our console application:

// C#
static void Main(string[] args)
{
    int left = int.Parse(args[0]);
    char theOperator = args[1][0];
    int right = int.Parse(args[2]);
    MathFunction mathFunction;
    if (theOperator == '+')
        mathFunction = Add;
    else if (theOperator == '-')
        mathFunction = Subtract;
    else if (theOperator == '*')
        mathFunction = Multiply;
    else
        mathFunction = Divide;
    PrintResult(mathFunction, left, right);
}
' Visual Basic
Sub Main(ByVal args() As String)
    Dim left As Integer = Integer.Parse(args(0))
    Dim theOperator As Char = args(1)(0)
    Dim right As Integer = Integer.Parse(args(2))
    Dim mathFunction As MathFunction
    If theOperator = "+" Then
        mathFunction = AddressOf Add
    ElseIf theOperator = "-" Then
        mathFunction = AddressOf Subtract
    ElseIf theOperator = "*" Then
        mathFunction = AddressOf Multiply
    Else
        mathFunction = AddressOf Divide
    End If
    PrintResult(mathFunction, left, right)
End Sub

Again, as in our JavaScript example, we declare a variable to hold our function and then perform some simple logic to assign the correct function. This, along with the two integers, is then passed to our PrintResult() method for output to the console.

Summary

In the strongly-typed .NET environment, delegates provide the means by which a variable or parameter can be specified as accepting a method with a particular signature.

Next: Anonymous Methods and Lambdas