Imagine that you have some code that iterates over a list of ints and prints them.
Now, suppose that you decide that you want your display method to display them in a different way. You actually want to write your list to a file rather than printing to the console, but you need to be backwards-compatible, so you need to retain the ability to simply print to console.
The first thing that you think of might be to create some sort of Handler object and call the equivalent of the handler.handle() method on it (this is essentially the strategy pattern, if you are interested). This is shown in the following example:
We have classes implementing the IDisplayHandler interface which display objects in different ways.
Example usage is shown below:
Lovely, you say. Where on earth do delegates come into this? Well, in C# you can use delegates to do make this solution much simpler.
Essentially, a delegate is a type which defines a method signature. An instance of a delegate can point to any method with the corresponding signature and delegates are used to pass around methods as parameters.
For example:
This defines a method signature which takes in two ints and returns one int. Let's understand this more clearly with a simple example based on our strategy pattern display example above.
Define a delegate using the delegate keyword.
This delegate will need to point to a method which takes in any object and returns void.
I know a method like this! The plain old Console.WriteLine().
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var myInts = new List<int>() | |
{ | |
1, | |
3, | |
4, | |
6, | |
}; | |
Display(myInts); | |
} | |
private static void Display<T>(IEnumerable<T> list ) | |
{ | |
foreach (var item in list) | |
{ | |
Console.WriteLine(item.ToString()); | |
} | |
} | |
} |
The first thing that you think of might be to create some sort of Handler object and call the equivalent of the handler.handle() method on it (this is essentially the strategy pattern, if you are interested). This is shown in the following example:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface IDisplayHander | |
{ | |
void Display(object o); | |
} | |
class SimpleConsoleDisplayer : IDisplayHander | |
{ | |
public void Display(object o) | |
{ | |
Console.WriteLine(o.ToString()); | |
} | |
} | |
class FileDisplayer : IDisplayHander | |
{ | |
public void Display(object o) | |
{ | |
var file = new System.IO.StreamWriter("output.txt"); | |
file.WriteLine(o.ToString()); | |
file.Close(); | |
} | |
} |
Example usage is shown below:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static void Main(string[] args) | |
{ | |
var myInts = new List<int>() | |
{ | |
1, | |
3, | |
4, | |
6, | |
}; | |
Display(myInts, new FileDisplayer()); | |
} | |
private static void Display<T>(IEnumerable<T> list, IDisplayHandler displayHandler) | |
{ | |
foreach (var item in list) | |
{ | |
displayHandler.Display(item); | |
} | |
} |
Introduction to Delegates
Essentially, a delegate is a type which defines a method signature. An instance of a delegate can point to any method with the corresponding signature and delegates are used to pass around methods as parameters.
For example:
public delegate int ExecuteCalculation(int x, int y);
This defines a method signature which takes in two ints and returns one int. Let's understand this more clearly with a simple example based on our strategy pattern display example above.
Simple Delegate Example
Define a delegate using the delegate keyword.
private delegate void DisplayIt(object o);
This delegate will need to point to a method which takes in any object and returns void.
I know a method like this! The plain old Console.WriteLine().
var display = new DisplayIt(Console.WriteLine());
All that remains is to pass it into the Display method which, instead of calling Console.Writeline() explicitly will simply pass the objects to the delegate which in turn calls its 'Invoke' method and VOILA, you have printed to the console.
The example below shows the complete code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private delegate void DisplayIt(object o); | |
static void Main(string[] args) | |
{ | |
var myInts = new List<int>() | |
{ | |
1, | |
3, | |
4, | |
6, | |
}; | |
//var display = new DisplayIt(Console.WriteLine); | |
var display = new DisplayIt(WriteToFile); | |
Display(myInts, display); | |
} | |
private static void WriteToFile(object o) | |
{ | |
using (StreamWriter w = File.AppendText("output.txt")) | |
{ | |
w.WriteLine(o.ToString()); | |
} | |
} | |
private static void Display<T>(IEnumerable<T> list, DisplayIt displayIt) | |
{ | |
foreach (var item in list) | |
{ | |
displayIt(item); | |
} | |
} |
No comments:
Post a Comment