【委托】—是什么&怎么用&什么用

本文通过一个生动的示例,详细介绍了委托的概念及其在编程中的应用。通过定义委托类型和事件,实现了不同类之间的解耦和方法的传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    最近在研究委托,在此跟大家分享一下。今天先说说委托是什么以及委托怎么用。

概念:

    官方的讲:委托就是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看做是对函数的抽象,是函数的"类",委托的实例将代表一个具体的函数。

    另一种教容易理解的解释:委托是一个类,它定义了方法的类型,使方法可以当作另一个方法的参数来进行传递

    为了让大家更好地理解,我再举个例子: 

实例:

 public void isontime()//到时间了,该去接孩子了
        {
            Console.WriteLine("妈妈:还没下班,怎么办\n");           
        }
    没关系呀,有保姆呢,委托给保姆去做就可以了。

 class mother
    {
        //声明委托help,即定义了一个方法的类型为 help。
        public delegate void help();
        //定义了一个help委托类型的事件。也可以理解为委托的实例。
        public event help delegation;

        public void istime()//到时间了,该去接孩子了
        {
            Console.WriteLine("妈妈:时间到了,该去接孩子了\n");
            //委托给保姆
            delegation();
        }      
    }
    保姆类:

class nurse
    {
        public void getorder()//收到命令
        {
            Console.WriteLine("保姆:收到");
            Console.WriteLine("保姆:孩子接回来了\n");          
        }
    }
    那妈妈怎么告诉保姆去接孩子呢?其实很好说,保姆本就有接孩子的职责,所以只需要妈妈说一声到时间了就可以了。

class main
    {
        static void Main(string[] args)
        {
            //实例化
            mother mom= new mother();
            nurse nur=new nurse();
            nurses nurs = new nurses();
            //将保姆的方法注册到妈妈
            mom.delegation += new mother.help(nur.getorder); 
            //妈妈:时间到了
            mom.istime();
            Console.Read();
        } 
    }

结果:

      这就是委托,和生活中委托的意思很相近。

    现在再来理解关于委托的官方解释,应该就不难了:

    委托就是一种引用方法的类型:

    public delegate void help();定义了一个方法的类型,即方法的类型为help。把方法当做参数传递的时候可以这样:function(help function1);

    一旦为委托分配了方法,委托将与该方法具有完全相同的行为

    如上面的例子:mom.delegation += new mother.help(nur.getorder); 给委托delegation分配了getorder方法,之后delegation(),就相当于getorder();


下面再借上面的例子说说使用委托的流程:

流程:

该委托是用到事件的:

    1.声明一个委托:

        public delegate void help();

    2.声明一个事件:

        public event help delegation;

    3.将被委托的方法注册到事件:

        mom.delegation += new mother.help(nur.getorder); //+=是注册,-=是注销

    4.触发需要委托的方法:

        mom.istime();

    5.需要委托的方法中有事件的触发

         public void istime()//到时间了,该去接孩子了
            {
                Console.WriteLine("妈妈:时间到了,该去接孩子了\n");
                //委托给保姆
                delegation();
            }

    6.而事件中注册了被委托的方法,所以被委托的方法被执行

        public void getorder()//不用担心
            {
                Console.WriteLine("保姆:收到");
                Console.WriteLine("保姆:孩子接回来了\n");          
            }

    

总结:

    面向对象的思想:职责分明。自己不用做的事,就委托给该干这事的人。

    通过委托,实现了mother和nurse之间的解耦。即mother要用nurse的方法,但没有直接调用。

    提高了代码的可扩展性,如果此时mother还有别的事情,如要买菜,就可以把买菜委托给另一个nurse,这时,只需要再添加一个nurse类,里面写上买菜的方法,在主方法中将买菜注册到委托的事件中。就可以实现委托另一个nurse去买菜了。整个过程不会对原有程序进行任何改动。所以使用委托,提高了程序的可扩展性。



    


<think>嗯,用户之前问了关于Action类和Invoke方法的问题,现在又问委托(delegate)怎么用以及委托到底是什么。看起来他们可能在学C#,特别是委托和事件处理这部分。需要先回顾一下之前的回答,确保内容连贯,但这次要更基础一些,因为用户现在问的是delegate的基础概念和使用方法。 首先,用户之前的问题已经涉及到了Action,而Action是预定义的委托类型。现在他们可能想了解更底层的委托机制,即如何自定义委托,而不仅仅是使用系统提供的Action或Func。因此,需要从委托的基本定义讲起,说明委托是什么,和类的关系,以及如何声明和使用。 用户可能对委托的概念还不太清楚,所以需要比喻或例子来帮助理解。比如,把委托比作函数指针,或者回调机制,这样更容易理解。另外,他们可能想知道为什么需要委托,以及在实际编程中委托的应用场景,比如事件处理、回调方法等。 接下来,用户的问题包括“delegate怎么用”,需要分步骤说明如何声明委托、实例化委托、多播委托等。要注意示例代码的简洁性,用简单的例子展示委托的定义和调用过程。同时,要对比系统内置的Action和Func,说明自定义委托和它们的区别,以及何时使用哪种更合适。 另外,用户可能对委托和事件的关系有疑问,虽然问题中没有提到事件,但可能需要简要提及,因为事件是基于委托的。但为了避免信息过载,可能先集中在委托本身,除非用户的问题扩展到事件。 还要注意用户可能遇到的常见错误,比如空引用异常,或者忘记取消订阅导致的内存泄漏。这些在之前的回答中也有提到,这里可以再次强调,以加强记忆。 最后,需要总结委托的核心要点,确保用户理解委托的作用、声明方法、使用场景和注意事项。使用列表或对比表格可以帮助整理信息,使其更清晰易懂。同时,提供实际的应用示例,如UI事件、异步回调等,让用户看到委托的实际价值。 总的来说,回答需要结构清晰,从定义到使用,再到实际应用和常见问题,逐步深入,避免使用过多专业术语,用简单易懂的语言和示例帮助用户建立对委托的全面理解。</think>以下是对C#委托(delegate)的完整解析,采用技术手册风格呈现: --- ### 一、委托本质解析 #### 1. 核心定义 - **类型本质**:委托是面向函数指针的类型安全封装类 - **核心能力**:实现方法引用的存储与传递 - **内存模型**:每个委托实例独立存储于堆内存中 #### 2. 技术定位 | 维度 | 描述 | |-------------|-------------------------------| | CLR类型 | 派生自`System.Delegate`的类 | | 编译产物 | 生成包含`Invoke`方法的完整类 | | 类型安全 | 强制校验方法签名匹配 | --- ### 二、委托声明规范 #### 1. 标准声明格式 ```csharp // 完整声明模板 [访问修饰符] delegate [返回值类型] 委托名([参数列表]); // 实际示例 public delegate void LogHandler(string message, int severity); ``` #### 2. 现代简化方案 ```csharp // 使用内置泛型委托替代自定义声明 Action<string, int> logAction; // 等效上述LogHandler ``` --- ### 三、委托操作全流程 #### 1. 基础使用步骤 ```csharp // 步骤1:声明委托类型 delegate void DataProcessor(int[] data); // 步骤2:定义匹配方法 void SortData(int[] arr) { Array.Sort(arr); } void PrintData(int[] arr) { Console.WriteLine(string.Join(",", arr)); } // 步骤3:实例化委托链 DataProcessor processor = SortData; processor += PrintData; // 多播委托 // 步骤4:触发执行 int[] numbers = {5,3,9}; processor(numbers); // 等效processor.Invoke(numbers) ``` #### 2. 参数传递机制 - **同步调用**:`Invoke()`直接在当前线程执行 - **异步调用**:`BeginInvoke()`启动独立线程 --- ### 四、委托与Lambda表达式 #### 1. 匿名方法绑定 ```csharp delegate int MathOp(int x, int y); MathOp add = delegate(int a, int b) { return a + b; }; // C# 2.0 MathOp multiply = (a, b) => a * b; // C# 3.0+ Lambda ``` #### 2. 闭包捕获示例 ```csharp int baseValue = 10; MathOp adder = x => x + baseValue; // 捕获外部变量 Console.WriteLine(adder(5)); // 输出15 ``` --- ### 五、关键应用场景 #### 1. 事件系统基础 ```csharp class TemperatureMonitor { // 声明基于委托的事件 public delegate void AlertHandler(float temp); public event AlertHandler OnOverheat; void CheckTemperature() { if(currentTemp > 100) { OnOverheat?.Invoke(currentTemp); // 触发警报 } } } ``` #### 2. 策略模式实现 ```csharp delegate bool FilterCondition(string item); void ProcessData(List<string> data, FilterCondition filter) { foreach(var item in data.Where(i => filter(i))) { // 处理符合条件的数据 } } // 使用示例 ProcessData(list, s => s.Length > 5); // Lambda条件 ``` --- ### 六、委托技术细节 #### 1. 内存结构剖析 ``` 委托实例内存布局: +-------------------+ | Method Pointer | -> 指向目标方法的地址 | Target Object | -> 实例方法的所属对象(静态方法为null) | Invocation List | -> 多播委托的方法链 +-------------------+ ``` #### 2. 性能优化要点 - 避免高频创建委托实例(可缓存复用) - 使用`MethodImplOptions.AggressiveInlining`优化小委托 - 对性能敏感场景优先使用静态方法 --- ### 七、委托与接口对比 | 维度 | 委托 | 接口 | |-----------------|-------------------------------|-------------------------------| | 绑定方法数 | 单方法/多播链 | 需实现多个方法 | | 版本兼容 | 新增方法不影响已有代码 | 新增方法破坏现有实现 | | 使用场景 | 事件回调、算法注入 | 定义对象契约 | | 运行时开销 | 调用成本较低 | 涉及虚方法表查询 | --- ### 八、调试与诊断 #### 1. 查看委托内容 ```csharp var delegates = myDelegate.GetInvocationList(); foreach(var d in delegates) { Console.WriteLine($"Method: {d.Method.Name}, Target: {d.Target}"); } ``` #### 2. 常见异常处理 - **NullReferenceException**:调用前检查null ```csharp if(myDelegate != null) { myDelegate(args); } ``` - **InvalidOperationException**:确保委托链未被修改 --- ### 九、现代C#演进 #### 1. 本地函数委托 ```csharp void ProcessData() { int counter = 0; // 本地函数作为委托 void Increment() { counter++; } var action = (Action)Increment; action(); } ``` #### 2. 函数指针(C# 9+) ```csharp unsafe { delegate* managed<int, int, int> funcPtr = &Add; int result = funcPtr(3, 5); } ``` --- ### 最佳实践原则 1. **命名规范**:委托类型以`Handler`或`Callback`结尾 2. **线程安全**:多线程环境使用`lock`保护委托链 3. **资源释放**:及时移除不需要的委托引用 4. **类型选择**:优先使用`Func<>`/`Action<>`简化声明 通过这个结构可以系统性地掌握C#委托的核心原理和实际应用技巧。建议通过Unity事件系统或ASP.NET Core中间件等具体场景加深理解。
评论 57
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值