Csharp Delegate
In C#, a Delegate is a type-safe function pointer that allows passing methods as parameters to other methods.
Delegates in C# are similar to function pointers in C or C++. A **Delegate** is a reference type variable that holds a reference to a method, and the reference can be changed at runtime.
Delegates are very common in C#, used for operations like event handling, callback functions, LINQ, etc.
All delegates are derived from the **System.Delegate** class.
A delegate is a reference type that defines a method signature and can be used to store a reference to a method with that signature. Through delegates, you can call methods in other classes.
A delegate declaration determines the methods that can be referenced by that delegate. A delegate can point to a method with the same signature.
The syntax for declaring a delegate is:
public delegate
Chinese format description:
public delegate return type delegate name(parameter type parameter name, ...);
For example, the following code defines a delegate that accepts two integers and returns an integer:
public delegate int MathOperation(int x, int y);
The following example delegate can be used to reference any method that takes a single _string_ parameter and returns an _int_ type variable.
public delegate int MyDelegate (string s);
Once a delegate type is declared, a delegate object must be created using the **new** keyword and associated with a particular method. When creating a delegate, the parameters passed to the **new** statement are written like a method call, but without parameters. For example:
public delegate void printString(string s);
...
printString ps1 =new printString(WriteToScreen);
printString ps2 =new printString(WriteToFile);
The following example demonstrates the declaration, instantiation, and use of a delegate that can reference a method with an integer parameter and returns an integer value.
## Example
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num =10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
// Create delegate instances
NumberChanger nc1 =new NumberChanger(AddNum);
NumberChanger nc2 =new NumberChanger(MultNum);
// Use delegate objects to call methods
nc1(25);
Console.WriteLine("Value of Num: {0}", getNum());
nc2(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
When the above code is compiled and executed, it produces the following result:
Value of Num: 35Value of Num: 175
Delegate objects can be combined using the + operator.
A combined delegate invokes each of the two delegates it combines. Only delegates of the same type can be combined.
The - operator can be used to remove a component delegate from a combined delegate.
Using this useful feature of delegates, you can create a call list of methods to be invoked when the delegate is called. This is known as **multicasting** of delegates, also called multicast.
The following program demonstrates delegate multicasting:
## Example
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num =10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
// Create delegate instances
NumberChanger nc;
NumberChanger nc1 =new NumberChanger(AddNum);
NumberChanger nc2 =new NumberChanger(MultNum);
nc = nc1;
nc += nc2;
// Invoke multicast
nc(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
When the above code is compiled and executed, it produces the following result:
Value of Num: 75
## Uses of Delegates
The following example demonstrates the use of delegates. The delegate _printString_ can be used to reference methods that take a string as input and return nothing.
We use this delegate to call two methods: the first prints a string to the console, and the second prints a string to a file:
## Example
using System;
using System.IO;
namespace DelegateAppl
{
class PrintString
{
static FileStream fs;
static StreamWriter sw;
// Delegate declaration
public delegate void printString(string s);
// This method prints to the console
public static void WriteToScreen(string str)
{
Console.WriteLine("The String is: {0}", str);
}
// This method prints to a file
public static void WriteToFile(string s)
{
fs =new FileStream("c:message.txt", FileMode.Append, FileAccess.Write);
sw =new StreamWriter(fs);
sw.WriteLine(s);
sw.Flush();
sw.Close();
fs.Close();
}
// This method takes a delegate as a parameter and uses it to call methods
public static void sendString(printString ps)
{
ps("Hello World");
}
static void Main(string[] args)
{
printString ps1 =new printString(WriteToScreen);
printString ps2 =new printString(WriteToFile);
sendString(ps1);
sendString(ps2);
Console.ReadKey();
}
}
}
When the above code is compiled and executed, it produces the following result:
The String is: Hello World
* * *
## Removing Delegates
If you no longer need a method, you can remove it from the delegate chain using the -= operator.
## Example
public class Program
{
public delegate void PrintMessage(string message);
public static void PrintUpperCase(string message)
{
Console.WriteLine(message.ToUpper());
}
public static void PrintLowerCase(string message)
{
Console.WriteLine(message.ToLower());
}
public static void Main()
{
PrintMessage print = PrintUpperCase;
print += PrintLowerCase;
// Remove the PrintLowerCase method
print -= PrintLowerCase;
// Invoke the delegate (only PrintUpperCase will be called)
print("Hello, C#");// Output: HELLO, C#
}
}
* * *
## Delegates and Events
Delegates are often used with Events, which are a special type of delegate used for the publish-subscribe mechanism.
In C#, an event is essentially a type that encapsulates a delegate, used to respond to certain actions in a program.
## Example
public class Button
{
// Define an event
public event EventHandler Click;
// Method to raise the event
public void OnClick()
{
if(Click !=null)
{
Click(this, EventArgs.Empty);// Invoke the event
}
}
}
public class Program
{
public static void Main()
{
Button button =new Button();
// Subscribe to the event
button.Click+= Button_Click;
// Raise the event
button.OnClick();// Output "Button clicked!"
}
private static void Button_Click(object sender, EventArgs e)
{
Console.WriteLine("Button clicked!");
}
}
* * *
## Types of Delegates
C# provides several common delegate types:
### 1γAction
**Action**: Represents a method that does not return a value. It can accept up to 16 parameters.
Action printMessage = Console.WriteLine; printMessage("Hello");
### 2γFunc
Func: Represents a method that returns a value. It accepts up to 16 parameters, where the first parameter is the input parameter and the last parameter is the return type.
Func add = (x, y) => x + y;Console.WriteLine(add(3, 4)); // Output 7
### 3γPredicate
Predicate: Represents a method that returns a bool value, typically used for conditional checks.
Predicate isEven = x => x % 2 == 0;Console.WriteLine(isEven(4)); // Output True
* * *
Notes on Delegates
**Type Safety:** Delegates are type-safe, meaning only methods with matching signatures can be assigned to a delegate.
Anonymous Methods and Lambda Expressions: You can use anonymous methods or lambda expressions to create delegate instances, simplifying the code.
Func add = (x, y) => x + y;Console.WriteLine(add(5, 3)); // Output 8
Asynchronous Calls: Delegates can be used with the BeginInvoke and EndInvoke methods for asynchronous calls.
Delegates are a very powerful and flexible feature in C#, helping to implement event-driven programming, callback mechanisms, and functional programming styles. They not only provide code reuse capabilities but also enhance the modularity of programs. Understanding and mastering the use of delegates is very important for C# programming.
YouTip