C# Delegates
C# Delegates
C# Delegates.........................................................................................................................................1 Overview of Delegates.....................................................................................................................1 Named Methods...............................................................................................................................2 Anonymous Methods.......................................................................................................................3 Action<T> and Func<T> delegates......................................................................................................4 Action Delegate...............................................................................................................................5 Func<TResult> Delegate.................................................................................................................7 Lambda Expressions (C# Programming Guide)............................................................................10 Bibliography ......................................................................................................................................11
C# Delegates
A delegate is a type that references a method. Once a delegate is assigned a method, it behaves exactly like that method. The delegate method can be used like any other method, with parameters and a return value, as in this example:
public delegate int PerformCalculation(int x, int y);
Overview of Delegates
Delegates have the following properties: Delegates are similar to C++ function pointers, but are type safe. Delegates allow methods to be passed as parameters. Delegates can be used to define callback methods. Delegates can be chained together; for example, multiple methods can be called on a single event. Methods don't need to match the delegate signature exactly. For more information, see Covariance and Contravariance C# version 2.0 introduces the concept of Anonymous Methods, which permit code blocks to be passed as parameters in place of a separately defined method.
Example:
// declare a delegate named Del that can encapsulate a method that takes a string as an argument and returns void: public delegate void Del(string message); // Create a method for a delegate. public static void DelegateMethod(string message) { System.Console.WriteLine(message);
} // Instantiate the delegate. Del handler = DelegateMethod; // Call the delegate. handler("Hello World");
Delegate types are derived from the Delegate class. Because the instantiated delegate is an object, it can be passed as a parameter, or assigned to a property. This allows a method to accept a delegate as a parameter, and call the delegate at some later time. This is known as an asynchronous callback
public void MethodWithCallback(int param1, int param2, Del callback) { callback("The number is: " + (param1 + param2).ToString()); } MethodWithCallback(1, 2, handler);
Named Methods
A delegate can be associated with a named method. When you instantiate a delegate using a named method, the method is passed as a parameter, for example:
// Declare a delegate: delegate void Del(int x); // Define a named method: void DoWork(int k) { /* ... */ } // Instantiate the delegate using the method as a parameter: Del d = obj.DoWork;
This is called using a named method. Delegates constructed with a named method can encapsulate either a static method or an instanced method. The following is a simple example of declaring and using a delegate. Notice that both the delegate, Del, and the associated method, MultiplyNumbers, have the same signature
// Declare a delegate delegate void Del(int i, double j); class MathClass { static void Main() { MathClass m = new MathClass();
// Delegate instantiation using "MultiplyNumbers" Del d = m.MultiplyNumbers; // Invoke the delegate object. System.Console.WriteLine("Invoking the delegate using 'MultiplyNumbers':"); for (int i = 1; i <= 5; i++) { d(i, 2); } } // Declare the associated method. void MultiplyNumbers(int m, double n) { System.Console.Write(m * n + " "); }
In the following example, one delegate is mapped to both static and instance methods and returns specific information from each.
// Declare a delegate delegate void Del(); class SampleClass { public void InstanceMethod() { System.Console.WriteLine("A message from the instance method."); } static public void StaticMethod() { System.Console.WriteLine("A message from the static method."); } } class TestSampleClass { static void Main() { SampleClass sc = new SampleClass(); // Map the delegate to the instance method: Del d = sc.InstanceMethod; d(); // Map to the static method: d = SampleClass.StaticMethod; d();
} }
Anonymous Methods
C# 2.0 introduces anonymous methods. Creating anonymous methods is essentially a way to pass a code block as a delegate parameter.
// Create a delegate instance delegate void Del(int x); // Instantiate the delegate using an anonymous method Del d = delegate(int k) { /* ... */ }; // Declare a delegate delegate void Printer(string s); class TestClass { static void Main() { // Instatiate the delegate type using an anonymous method: Printer p = delegate(string j) { System.Console.WriteLine(j); }; // Results from the anonymous delegate call: p("The delegate using the anonymous method is called."); // The delegate instantiation using a named method "DoWork": p = new Printer(TestClass.DoWork); // Results from the old style delegate call: p("The delegate using the named method is called."); } // The method associated with the named delegate: static void DoWork(string k) { System.Console.WriteLine(k); }
The Func<T> delegates can be used in a similar manner. Func<T> allows you to invoke methods with a return type. Similar to Action<T>, Func<T> is defined in different variants to pass up to 16 parameter types and a return type. Func<out TResult> is the delegate type to invoke a method with a return type and without parameters. Func<in T, out TResult> is for a method with one parameter, and Func<in T1, in T2, in T3, in T4, out TResult> is for a method with four parameters. Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> Delegate Encapsulates a method that has 16 parameters and does not return a value. Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult> Delegate Encapsulates a method that has 16 parameters and returns a value of the type specified by the TResult parameter.
Action Delegate
Encapsulates a method that has no parameters and does not return a value. The following code explicitly declares a delegate named ShowValue and assigns a reference to the Name.DisplayToWindow instance method to its delegate instance.
using System; using System.Windows.Forms; public delegate void ShowValue(); public class Name { private string instanceName; public Name(string name) { this.instanceName = name; } public void DisplayToConsole() { Console.WriteLine(this.instanceName); } public void DisplayToWindow() { MessageBox.Show(this.instanceName); }
public class testTestDelegate { public static void Main() { Name testName = new Name("Koani"); ShowValue showMethod = testName.DisplayToWindow; showMethod(); } }
The following example simplifies this code by instantiating the Action delegate instead of explicitly defining a new delegate and assigning a named method to it.
using System; using System.Windows.Forms; public class Name { private string instanceName; public Name(string name) { this.instanceName = name; } public void DisplayToConsole() { Console.WriteLine(this.instanceName); } public void DisplayToWindow() { MessageBox.Show(this.instanceName); }
public class testTestDelegate { public static void Main() { Name testName = new Name("Koani"); Action showMethod = testName.DisplayToWindow; showMethod(); } }
You can also use the Action delegate with anonymous methods in C#, as the following example illustrates.
using System; using System.Windows.Forms; public class Name { private string instanceName; public Name(string name) { this.instanceName = name; } public void DisplayToConsole() { Console.WriteLine(this.instanceName); } public void DisplayToWindow() { MessageBox.Show(this.instanceName);
public class Anonymous { public static void Main() { Name testName = new Name("Koani"); Action showMethod = delegate() { testName.DisplayToWindow();} ; showMethod(); } }
You can also assign a lambda expression to an Action delegate instance, as the following example illustrates.
using System; using System.Windows.Forms; public class Name { private string instanceName; public Name(string name) { this.instanceName = name; } public void DisplayToConsole() { Console.WriteLine(this.instanceName); } public void DisplayToWindow() { MessageBox.Show(this.instanceName); } } public class LambdaExpression { public static void Main() { Name testName = new Name("Koani"); Action showMethod = () => testName.DisplayToWindow(); showMethod(); } }
Func<TResult> Delegate
Encapsulates a method that has no parameters and returns a value of the type specified by the TResult parameter.
public delegate TResult Func<out TResult>()
The following code explicitly declares a delegate named WriteMethod and assigns a reference to the OutputTarget.SendToFile instance method to its delegate instance.
using System; using System.IO; delegate bool WriteMethod(); public class TestDelegate { public static void Main() { OutputTarget output = new OutputTarget(); WriteMethod methodCall = output.SendToFile; if (methodCall()) Console.WriteLine("Success!"); else Console.WriteLine("File write operation failed."); } } public class OutputTarget { public bool SendToFile() { try { string fn = Path.GetTempFileName(); StreamWriter sw = new StreamWriter(fn); sw.WriteLine("Hello, World!"); sw.Close(); return true; } catch { return false; } } }
The following example simplifies this code by instantiating the Func<TResult> delegate instead of explicitly defining a new delegate and assigning a named method to it.
using System; using System.IO; public class TestDelegate { public static void Main() { OutputTarget output = new OutputTarget(); Func<bool> methodCall = output.SendToFile; if (methodCall()) Console.WriteLine("Success!"); else Console.WriteLine("File write operation failed."); } } public class OutputTarget
public bool SendToFile() { try { string fn = Path.GetTempFileName(); StreamWriter sw = new StreamWriter(fn); sw.WriteLine("Hello, World!"); sw.Close(); return true; } catch { return false; } }
You can use the Func<TResult> delegate with anonymous methods in C#, as the following example illustrates.
using System; using System.IO; public class Anonymous { public static void Main() { OutputTarget output = new OutputTarget(); Func<bool> methodCall = delegate() { return output.SendToFile(); }; if (methodCall()) Console.WriteLine("Success!"); else Console.WriteLine("File write operation failed."); } } public class OutputTarget { public bool SendToFile() { try { string fn = Path.GetTempFileName(); StreamWriter sw = new StreamWriter(fn); sw.WriteLine("Hello, World!"); sw.Close(); return true; } catch { return false; } } }
You can also assign a lambda expression to a Func<T, TResult> delegate, as the following
example illustrates.
using System; using System.IO; public class Anonymous { public static void Main() { OutputTarget output = new OutputTarget(); Func<bool> methodCall = () => output.SendToFile(); if (methodCall()) Console.WriteLine("Success!"); else Console.WriteLine("File write operation failed."); } } public class OutputTarget { public bool SendToFile() { try { string fn = Path.GetTempFileName(); StreamWriter sw = new StreamWriter(fn); sw.WriteLine("Hello, World!"); sw.Close(); return true; } catch { return false; } } }
Bibliography
Delegates (C# Programming Guide) http://msdn.microsoft.com/en-us/library/ms173171%28v=vs.80%29.aspx Delegates Tutorial http://msdn.microsoft.com/en-us/library/aa288459%28v=vs.71%29.aspx Action Delegate http://msdn.microsoft.com/en-us/library/system.action.aspx Func<TResult> Delegate http://msdn.microsoft.com/en-us/library/bb534960.aspx [2010] Professional C# 4 And .Net 4.pdf