在C#中,delegate
是一种类型安全的委托类型,它用于引用方法。可以将方法作为参数传递给其他方法,或者动态选择在运行时调用哪个方法。delegate
可以看作是对方法的引用类型,它提供了一种将方法视作对象来处理的机制。
1. 基本概念:什么是委托 (delegate
)?
委托类似于函数指针的概念,但与C/C++中的函数指针不同,C#中的委托是类型安全的,并且只能引用与其签名匹配的方法(即返回类型和参数类型一致)。
示例:定义和使用委托
// 定义一个委托类型,它可以引用返回类型为 void,参数为 string 的方法
public delegate void PrintMessage(string message);
class Program
{
// 定义一个与委托匹配的方法
public static void PrintToConsole(string message)
{
Console.WriteLine(message);
}
static void Main(string[] args)
{
// 创建一个委托实例,指向 PrintToConsole 方法
PrintMessage printer = PrintToConsole;
// 调用委托,它会调用 PrintToConsole 方法
printer("Hello, Delegate!"); // 输出:Hello, Delegate!
}
}
在这个示例中:
delegate void PrintMessage(string message);
定义了一个委托类型PrintMessage
,它可以引用任何返回void
且接受string
参数的方法。- 在
Main
方法中,printer
是一个委托实例,指向PrintToConsole
方法。通过printer("Hello, Delegate!")
,委托调用了PrintToConsole
方法。
2. 委托的签名
委托的签名决定了它可以引用什么样的方法。只有当方法的返回类型和参数类型与委托的签名匹配时,才能被该委托引用。
示例:不同的委托签名
// 定义不同的委托类型
public delegate int Calculate(int a, int b); // 返回 int,接受两个 int 参数
public delegate string GetMessage(); // 返回 string,没有参数
public delegate void ProcessData(int data); // 返回 void,接受一个 int 参数
class Program
{
// 与 Calculate 委托匹配的方法
public static int Add(int x, int y) => x + y;
public static int Multiply(int x, int y) => x * y;
// 与 GetMessage 委托匹配的方法
public static string WelcomeMessage() => "Welcome!";
// 与 ProcessData 委托匹配的方法
public static void DisplayData(int data) => Console.WriteLine($"Data: {data}");
static void Main(string[] args)
{
// 使用不同的委托
Calculate calc = Add;
Console.WriteLine(calc(3, 4)); // 输出:7
calc = Multiply;
Console.WriteLine(calc(3, 4)); // 输出:12
GetMessage msg = WelcomeMessage;
Console.WriteLine(msg()); // 输出:Welcome!
ProcessData processData = DisplayData;
processData(100); // 输出:Data: 100
}
}
3. 多播委托
委托还可以同时引用多个方法,这称为多播委托。当多播委托被调用时,它会依次调用每个方法。如果委托有返回值,只有最后一个方法的返回值会被保留。
示例:多播委托
public delegate void Notify();
class Program
{
public static void NotifyByEmail()
{
Console.WriteLine("Notified by Email");
}
public static void NotifyBySMS()
{
Console.WriteLine("Notified by SMS");
}
static void Main(string[] args)
{
// 创建多播委托
Notify notify = NotifyByEmail;
notify += NotifyBySMS;
// 调用多播委托
notify(); // 输出:
// Notified by Email
// Notified by SMS
}
}
在这个例子中,notify
委托依次调用了 NotifyByEmail
和 NotifyBySMS
方法。
4. 委托作为参数
可以将委托作为参数传递给其他方法,这样可以实现更灵活的代码设计。
示例:委托作为参数
public delegate void ActionDelegate(string message);
class Program
{
// 定义一个方法,接受一个委托作为参数
public static void ExecuteAction(ActionDelegate action, string message)
{
action(message); // 调用传入的委托
}
public static void PrintToUpper(string message)
{
Console.WriteLine(message.ToUpper());
}
static void Main(string[] args)
{
ActionDelegate action = PrintToUpper;
ExecuteAction(action, "Hello, Delegate!"); // 输出:HELLO, DELEGATE!
}
}
在这个示例中,ExecuteAction
方法接受一个委托作为参数,它通过委托调用传入的方法。
5. 匿名方法和 Lambda 表达式
C# 支持使用匿名方法或 Lambda 表达式创建委托,而不需要显式定义方法。这使得代码更简洁,尤其在只需使用一次的方法时。
5.1 匿名方法
public delegate void Display(string message);
class Program
{
static void Main(string[] args)
{
// 使用匿名方法创建委托
Display display = delegate(string msg)
{
Console.WriteLine(msg);
};
display("Hello, Anonymous Method!"); // 输出:Hello, Anonymous Method!
}
}
5.2 Lambda 表达式
Lambda 表达式是匿名方法的简洁语法,通常用于委托和事件处理。
public delegate void Display(string message);
class Program
{
static void Main(string[] args)
{
// 使用 Lambda 表达式创建委托
Display display = (msg) => Console.WriteLine(msg);
display("Hello, Lambda!"); // 输出:Hello, Lambda!
}
}
6. 内置委托类型:Action
和 Func
C# 提供了内置的委托类型 Action
和 Func
,用于简化常见的委托场景:
Action
:表示一个返回void
的委托,可以有 0 到 16 个输入参数。Func
:表示一个有返回值的委托,可以有 0 到 16 个输入参数,最后一个泛型参数为返回类型。
示例:使用 Action
和 Func
class Program
{
static void Main(string[] args)
{
// 使用 Action
Action<string> print = (msg) => Console.WriteLine(msg);
print("Hello, Action!"); // 输出:Hello, Action!
// 使用 Func
Func<int, int, int> add = (x, y) => x + y;
Console.WriteLine(add(3, 4)); // 输出:7
}
}
总结
- 委托 (
delegate
) 是 C# 中用于引用方法的类型,可以动态选择和调用方法。 - 多播委托 允许一个委托同时引用多个方法。
- 匿名方法和 Lambda 表达式 是创建委托的简洁方式。
- 内置的
Action
和Func
委托类型简化了常见的委托定义。