差别
这里会显示出您选择的修订版和当前版本之间的差别。
| 后一修订版 | 前一修订版 | ||
| csharp:类:委托 [2025/09/28 16:58] – 创建 张叶安 | csharp:类:委托 [2025/11/27 10:15] (当前版本) – [1. 简介] 张叶安 | ||
|---|---|---|---|
| 行 1: | 行 1: | ||
| - | 90-70-1:简介 | + | ====== C# 委托 (Delegate) 深度解析 ====== |
| - | 关键字:delegate(de li gi t) | + | 委托是 |
| - | + | ||
| - | 委托就是将方法(函数)当作变量进行处理! | + | |
| - | delegate与类同级(类外创建) 声明委托的格式要与指向函数格式一样 | + | ===== 1. 简介 ===== |
| - | {{.:pasted: | + | **关键字**:%%delegate%% (读音: /' |
| - | 要使用委托时, | + | **核心概念**: |
| + | * 委托将**方法(函数)当作变量**进行处理。 | ||
| + | * 委托是一种**引用类型**,它定义了方法的签名(Signature)。 | ||
| + | * 只要方法的签名(返回值类型 + 参数列表)与委托定义一致,该方法就可以赋值给委托变量。 | ||
| - | 1:要像类一样先声明定义一个委托类型、[是否带有参数或返回值] | ||
| - | | + | **通俗理解**:委托就像是一个“办事处代表”。你定义了这个代表能办什么事(比如能接收两个整数,返回一个整数)。任何符合这个标准的具体办事员(具体方法),都可以被指派给这个代表去执行任务。 |
| - | + | ||
| - | 2:在实例化委托、指向一个函数 | + | |
| - | | ||
| - | |||
| - | 如果没有指像一个函数代表、仅仅只是委托待发布而已 | ||
| - | | ||
| - | 系统预定义委托格式(系统定义好的委托、直接用就行) | ||
| - | Action(A e k xing): | + | ===== 2. 委托的使用步骤 ===== |
| - | Func< | + | 使用自定义委托通常分为三步: |
| - | 系统预定义委托格式好处不用自己定义委托及格式 | + | - **定义 |
| + | - **实例化 (Instantiate)**:创建委托对象,并指向一个具体的方法。 | ||
| + | - **调用 (Invoke)**:像调用函数一样调用委托对象。 | ||
| + | <code csharp> | ||
| + | // 1. 声明委托 (规定了必须是:两个int参数,返回bool) | ||
| + | public delegate bool CompareDelegate(int a, int b); | ||
| - | |||
| - | 90-70-2:委托案例1[自定义委托] | ||
| - | ``` | ||
| - | using System; | ||
| - | // 定义一个委托类型,它接受两个整数参数并返回一个布尔值结果 | ||
| - | public delegate bool CompareDelegate(int a, int b); | ||
| class Program | class Program | ||
| { | { | ||
| static void Main() | static void Main() | ||
| { | { | ||
| - | // 创建一个委托实例,并将其指向IsGreater方法 | + | // 2. 实例化委托,指向 IsGreater 方法 |
| + | // 注意:这里只写方法名,不要带括号() | ||
| CompareDelegate compare = IsGreater; | CompareDelegate compare = IsGreater; | ||
| - | // 调用委托实例,实际上调用的是IsGreater方法 | + | // 3. 调用委托 |
| bool result = compare(5, 3); | bool result = compare(5, 3); | ||
| - | Console.WriteLine(" | + | Console.WriteLine($"Is 5 greater than 3? {result}" |
| } | } | ||
| - | // 定义一个与委托签名匹配的方法 | + | // 具体方法:签名必须与委托一致 |
| static bool IsGreater(int a, int b) | static bool IsGreater(int a, int b) | ||
| { | { | ||
| 行 54: | 行 47: | ||
| } | } | ||
| } | } | ||
| - | ``` | + | </ |
| - | 在这个示例中,我们首先定义了一个名为`CompareDelegate`的委托类型,它接受两个整数参数并返回一个布尔值结果。 | + | ===== 3. 委托应用场景举例 ===== |
| - | 然后,我们在`Main`方法中创建了一个`CompareDelegate`类型的委托实例`compare`,并将其指向了`IsGreater`方法。 | + | ==== 案例 1:逻辑解耦 (字符串过滤器) ==== |
| - | 最后,我们通过调用委托实例`compare`来间接调用`IsGreater`方法,并将结果输出到控制台。 | + | 委托允许我们将判断逻辑从主流程中剥离出来。 |
| - | # 委托案例2[自定义委托] | + | <code csharp> |
| - | ``` | + | |
| using System; | using System; | ||
| - | // 定义一个委托类型,它接受一个字符串参数并返回一个布尔值结果 | + | // 定义委托:接收 string,返回 |
| - | public | + | public delegate bool StringFilter(string input); |
| class Program | class Program | ||
| 行 73: | 行 65: | ||
| static void Main() | static void Main() | ||
| { | { | ||
| - | // 实例化一个委托对象,并将其指向IsLongEnough方法 | + | // 这里的逻辑是可以动态替换的 |
| StringFilter filter = IsLongEnough; | StringFilter filter = IsLongEnough; | ||
| - | | + | bool result = filter(" |
| - | | + | Console.WriteLine($"Is ' |
| - | Console.WriteLine(" | + | |
| - | // 输出:Is ' | + | |
| } | } | ||
| - | // 定义一个与委托签名匹配的方法返回值与参数一致 | ||
| static bool IsLongEnough(string input) | static bool IsLongEnough(string input) | ||
| { | { | ||
| 行 88: | 行 77: | ||
| } | } | ||
| } | } | ||
| + | </ | ||
| - | ``` | + | ==== 案例 2:跨类调用 ==== |
| - | # 委托案例3[一个类调用另外另一个类的方法] | + | 如果委托需要指向另一个类的方法,需要先实例化那个类。 |
| - | 如果一个主类里面的委托想要、指向另外一个类里面的成员函数、 | + | <code csharp> |
| - | + | ||
| - | 则需要在主类里面、实例化该类的对象、 | + | |
| - | + | ||
| - | 再用委托的变量等于该类点方法即可、 | + | |
| - | + | ||
| - | ``` | + | |
| class Program | class Program | ||
| - | | + | { |
| - | // | + | // 自定义委托类型 |
| - | public | + | public delegate int MathOpDelegate(int a, int b); |
| - | | + | |
| - | { | + | |
| - | // | + | |
| - | jiahuna jiahuna_duixiang = new jiahuna(); | + | |
| - | // | + | |
| - | Delegate_fion weituo = jiahuna_duixiang.fangfa1;// | + | |
| - | // | + | |
| - | int NUM = weituo(5, 7); | + | |
| - | // | + | |
| - | Console.WriteLine(NUM); | + | |
| - | Console.ReadKey(); | + | |
| - | } | + | |
| - | } | + | |
| - | class jiahuna | + | |
| { | { | ||
| - | public int fangfa1( int a , int b) | + | // 1. 实例化包含方法的类 |
| - | | + | Calculator calc = new Calculator(); |
| - | int max = a * b; | + | |
| - | | + | // 2. 委托指向该实例的成员方法 |
| - | + | MathOpDelegate myDelegate | |
| - | } | + | |
| + | // 3. 执行委托 | ||
| + | int result = myDelegate(5, | ||
| + | |||
| + | | ||
| } | } | ||
| - | ``` | + | } |
| - | # 系统预定义Action委托 | + | class Calculator |
| - | + | ||
| - | Action委托是一种特殊的委托类型,它表示一个没有返回值的方法。下面是一个使用Action委托的示例: | + | |
| - | + | ||
| - | ``` | + | |
| - | using System; | + | |
| - | class Program | + | |
| { | { | ||
| - | | + | |
| - | { | + | |
| - | // 创建一个Action委托实例,并将其指向PrintMessage方法 | + | |
| - | Action< | + | |
| - | + | ||
| - | // 调用委托实例,实际上调用的是PrintMessage方法 | + | |
| - | print(" | + | |
| - | } | + | |
| - | + | ||
| - | // 定义一个与Action委托签名匹配的方法 | + | |
| - | static void PrintMessage(string message) | + | |
| { | { | ||
| - | | + | |
| } | } | ||
| } | } | ||
| - | ``` | + | </ |
| - | 在这个示例中,我们首先定义了一个名为`PrintMessage`的方法,它接受一个字符串参数并打印到控制台。 | + | ===== 4. 系统预定义委托 (Action & Func) ===== |
| - | 然后,我们在`Main`方法中创建了一个`Action< | + | 为了避免每次使用委托都要先写 |
| - | 最后,我们通过调用委托实例`print`来间接调用`PrintMessage`方法,并将结果输出到控制台。 | + | ^ 委托类型 ^ 返回值 ^ 用途 ^ 格式示例 ^ |
| + | | **Action** | **无 (void)** | 执行动作,不需结果 | %%Action< | ||
| + | | **Func** | **有 (TResult)** | 计算并返回结果 | ||
| - | # 系统预定义Func委托1 | + | ==== Action |
| - | 在C#中,`Func<T1, T2, ..., TResult>`委托表示一个接受指定数量的输入参数并返回结果的方法。它的参数类型由泛型参数 `T1, T2, ..., TResult` 定义。 | + | `Action` 后面尖括号里的类型全是**输入参数**。 |
| - | 具体来说,`Func<T1, T2, ..., TResult>` 委托有以下特点: | + | <code csharp> |
| + | static void Main() | ||
| + | { | ||
| + | // Action< | ||
| + | Action< | ||
| - | - `T1, T2, ...`: 这些是输入参数的类型,可以是任何有效的 C# 类型,包括值类型、引用类型和自定义类型。 | + | print(" |
| - | - `TResult`: 这是委托返回的结果类型,也可以是任何有效的 C# 类型。 | + | } |
| - | 例如,以下是一个使用 `Func` 委托的示例,它接受两个整数作为输入参数,并返回它们的和: | + | static void PrintMessage(string message) |
| + | { | ||
| + | Console.WriteLine(message); | ||
| + | } | ||
| + | </ | ||
| - | ``` | + | ==== Func 委托 (有返回值) ==== |
| - | using System; | + | |
| - | class Program | + | `Func` 后面尖括号里,**最后一个类型永远是返回值类型**,前面的都是输入参数类型。 |
| + | |||
| + | <code csharp> | ||
| + | static void Main() | ||
| { | { | ||
| - | | + | |
| - | | + | |
| - | // 创建一个Func委托实例,并将其指向Add方法 | + | // 输入参数2: |
| - | Func< | + | // 返回值: int |
| + | | ||
| - | // 调用委托实例,实际上调用的是Add方法 | + | |
| - | | + | Console.WriteLine($"3 + 4 = {sum}"); |
| - | Console.WriteLine(" | + | |
| - | } | + | |
| - | + | ||
| - | // 定义一个与Func委托签名匹配的方法 | + | |
| - | static int Add(int a, int b) | + | |
| - | { | + | |
| - | return a + b; | + | |
| - | } | + | |
| } | } | ||
| - | ``` | ||
| - | |||
| - | 在这个示例中,我们创建了一个 `Func< | ||
| - | # 系统预定义Func委托2 | + | static |
| - | ``` | + | |
| - | static | + | |
| { | { | ||
| - | Func< | + | return a + b; |
| - | // | + | |
| - | int he = jshuan(1, 2);// | + | |
| - | Console.WriteLine(he);// | + | |
| } | } | ||
| - | static int Jshuan(int a ,int b)// 方法2(用委托调用) | + | </code> |
| - | { | + | |
| - | int Xmod=a + b; | + | |
| - | return Xmod; | + | |
| - | } | + | |
| - | ``` | + | |
| - | # 匿名方法 | + | ===== 5. 匿名方法与 Lambda 表达式 ===== |
| - | {{.: | + | 有时我们只需要一个简单的逻辑,专门写一个静态函数太麻烦,这时可以使用匿名方法。 |
| - | 了解匿名方法前要了解以下: | + | ==== 匿名方法 |
| - | 委托就是将方法(函数)当作变量进行处理! | + | 在实例化委托时,直接使用 `delegate` 关键字定义方法体。 |
| - | 在实例化委托使、需要指向一个函数 | + | <code csharp> |
| + | public delegate int MathDelegate(int a, int b); | ||
| - | 若使用匿名方法则在创建委托对象时、同步创建该方法体、 | + | static void Main(string[] args) |
| + | { | ||
| + | // 直接内联定义逻辑,没有方法名 | ||
| + | MathDelegate multiply = delegate (int a, int b) | ||
| + | { | ||
| + | return a * b; | ||
| + | }; | ||
| - | ``` | + | int result = multiply(5, 7); |
| - | class Program | + | Console.WriteLine(result); |
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== 知识拓展:Lambda 表达式 (C# 3.0+ 推荐写法) ==== | ||
| + | |||
| + | 现代 C# 开发中,几乎不再使用 | ||
| + | |||
| + | <code csharp> | ||
| + | static void Main(string[] args) | ||
| { | { | ||
| - | | + | |
| - | public | + | // => 读作 "goes to" |
| - | static void Main(string[] args) | + | Func< |
| - | { | + | |
| - | //使用匿名方法创建委托对象[同步创建方法体] | + | int result |
| - | | + | Console.WriteLine(result); |
| - | { | + | } |
| - | return | + | </code> |
| - | }; | + | |
| - | // | + | ===== 总结 ===== |
| - | | + | |
| - | // | + | |
| - | | + | |
| - | | + | |
| - | } | + | |
| - | } | + | |
| - | ``` | + | |
| + | - **定义**:委托是方法的容器,可以把方法当参数传递。 | ||
| + | - **自定义**:使用 `delegate` 关键字定义签名。 | ||
| + | - **系统内置**: | ||
| + | - `Action`: 无返回值。 | ||
| + | - `Func`: 有返回值(最后一个泛型参数是返回类型)。 | ||
| + | - **进化**:从 `自定义委托` -> `Action/ | ||