C#中Delegate类的使用

本文介绍了C#中的委托(Delegate)类,包括其基本概念、简单应用示例以及如何利用委托实现多态。此外还对比了使用Delegate与Override实现多态的区别,并展示了多播委托(MulticastDelegate)的应用。

Delegate类简介
------------------------     
命名空间:System
程序集:mscorlib(在 mscorlib.dll 中)

   委托(Delegate)类是一种数据结构,通过它可引用静态方法或引用类实例及该类的实例方法。
以往的界面编程中我们应该都接触过各种类型的事件驱动(event driven)的处理模式,
在这种模式里,我们定义相应事件触发的函数。
例如:
Button1 的 Click事件,我们可以编写Button1_Click 或 Btn1Clicked等函数来做相应的驱动处理。
而事件与驱动函数的对应关系就是通过委托(Delegate)类来关联的。

其实委托(Delegate)类这种数据结构有些类似于之前C/C++中的函数指针。


Delegate类一个简单应用
------------------------    
1.定义一个Delegate函数数据结构
2.定义Delegate将引用的静态方法或引用类实例及该类的实例方法
3.Delegate数据变量指向实例方法
4.通过Delegate数据变量执行实例方法

A very basic example (TestClass.cs):

using System;

namespace MySample
{
    class TestClass
    {
    //1.定义一个Delegate函数数据结构
        public delegate void GoDelegate();

        [STAThread]
        static void Main(string[] args)
        {
        //3.Delegate数据变量指向实例方法
            GoDelegate goDelegate = new GoDelegate( MyDelegateFunc);

        //4.通过Delegate数据变量执行实例方法
            goDelegate();
            return;
        }
  
        //2.定义Delegate将引用的静态方法或引用类实例及该类的实例方法
        public static void MyDelegateFunc()
        {
            Console.WriteLine("delegate function...");
        }       
    }
}

编译执行结果:

# TestClass.exe
delegate function...

使用Delegate类和Override实现多态的比较
-----------------------------------------------
1.使用Delegate类的时候,下面的例子可以很清楚的说明。
  1.1 首先定义一个动物基类(MyAnimalDelegateClass), 基类中有显示属性的(ShowAnimalType)的public方法。
      并且在ShowAnimalType方法中调用Delegate引用的实例方法

  1.2 定义狮子(LionDelegateClass)和马(HorseDelegateClass)两个子类。Delegate与各自的实例方法绑定
      实现不同的属性显示(ShowAnimalType)方法。

////Delegate example (TestClass.cs):

using System;

namespace MySample
{
   class TestClass
   {
      [STAThread]
      static void Main(string[] args)
      {
      //狮子(LionDelegateClass)的属性显示(ShowAnimalType)方法调用
         LionDelegateClass lionDelegate = new LionDelegateClass();
         lionDelegate.ShowAnimalType("MySample");

      //马(HorseDelegateClass)的属性显示(ShowAnimalType)方法调用
         HorseDelegateClass horseDelegate = new HorseDelegateClass();
         horseDelegate.ShowAnimalType("MySample");
      }
   }

   //动物基类(MyAnimalDelegateClass)
   public class MyAnimalDelegateClass
   {
      //Delegate数据结构定义
      public delegate void DelegateFunction(string strFuncName);

      private DelegateFunction m_delegateFunction = null;

      //Delegate类型的属性
      public DelegateFunction delegateFunction
      {
         get
         {
            return m_delegateFunction;
         }
         set
         {
            m_delegateFunction = value;
         }
      }
   
      //属性显示(ShowAnimalType)方法
      public void ShowAnimalType(string strFuncName)
      {
         if (delegateFunction != null)
         {
            object[] args = {strFuncName};
         //调用Delegate引用的实例方法
            delegateFunction.DynamicInvoke(args);
         }
      }
   }

   //狮子(LionDelegateClass)
   public class LionDelegateClass:MyAnimalDelegateClass
   {
      public LionDelegateClass()
      {
         this.delegateFunction = new DelegateFunction(subFunction1);
      }

      //狮子(LionDelegateClass)实例方法的实装
      private void subFunction1(string strFuncName)
      {
         System.Console.WriteLine(
            string.Format("[{0}]This is a lion....", strFuncName));
      }
   }

   //马(HorseDelegateClass)
   public class HorseDelegateClass:MyAnimalDelegateClass
   {
      public HorseDelegateClass()
      {
         this.delegateFunction = new DelegateFunction(subFunction2);
      }

      //马(HorseDelegateClass)实例方法的实装
      private void subFunction2(string strFuncName)
      {
         System.Console.WriteLine(
            string.Format("[{0}]This is a horse....", strFuncName));
      }
   }
}

编译执行结果:

# TestClass.exe

[MySample]This is a lion....
[MySample]This is a horse....

2.使用Override实装的时候,参考下面的例子。
  1.1 首先定义一个动物基类(AbstractAnimalNoDelegateClass), 基类中有显示属性的(ShowAnimalType)的public方法。
      并且在ShowAnimalType方法中调用抽象方法(NoDelegateFunction)

  1.2 定义狮子(LionNoDelegateClass)和马(HorseNoDelegateClass)两个子类。
      子类中实装抽象方法(NoDelegateFunction)
      实现不同的属性显示(ShowAnimalType)方法。


////Override example (TestClass.cs):

using System;

namespace MySample
{
   class TestClass
   {
      [STAThread]
      static void Main(string[] args)
      {
          //狮子(LionNoDelegateClass )的属性显示(ShowAnimalType)方法调用
          LionNoDelegateClass lionNoDelegate = new LionNoDelegateClass();
       lionNoDelegate.ShowAnimalType("MySample");

          //马(HorseNoDelegateClass )的属性显示(ShowAnimalType)方法调用
       HorseNoDelegateClass horseNoDelegate = new HorseNoDelegateClass();
       horseNoDelegate.ShowAnimalType("MySample");
      }
   }

   //动物基类(AbstractAnimalNoDelegateClass)
    public abstract class AbstractAnimalNoDelegateClass
    {
        public void ShowAnimalType(string strFuncName)
        {
            //抽象方法(NoDelegateFunction)调用
            NoDelegateFunction(strFuncName);
        }
        //在基类中定义抽象方法(NoDelegateFunction)
        protected abstract void NoDelegateFunction(string strFuncName);
    }

    //狮子(LionNoDelegateClass )
    public class LionNoDelegateClass:AbstractAnimalNoDelegateClass
    {
    // 子类中实装抽象方法(NoDelegateFunction)
        protected override void NoDelegateFunction(string strFuncName)
        {
            System.Console.WriteLine(
                string.Format("[{0}]This is a lion....", strFuncName));
        }
    }
   
   //马(HorseNoDelegateClass )
    public class HorseNoDelegateClass:AbstractAnimalNoDelegateClass
    {
    // 子类中实装抽象方法(NoDelegateFunction)
        protected override void NoDelegateFunction(string strFuncName)
        {
            System.Console.WriteLine(
                string.Format("[{0}]This is a horse....", strFuncName));
        }
    }
}

编译执行结果:

# TestClass.exe

[MySample]This is a lion....
[MySample]This is a horse....

3.比较Delegate和Override实装方式
  可以看出Delegate实装方式中,相当于定义一个函数指针的成员变量。
  通过把实装函数的地址赋给该成员变量,实现同样的方法,处理方式的不同。
  而Override方式中,则是在父类中预先定义好接口,通过实装的不同,
  来实现同样的方法,处理方式的不同。
  Delegate实装方式比较灵活,适合设计不是很完善的场合,便于修改。
  Override方式封装性好,相对比较安全。

MulticastDelegate 类的应用
---------------------------------
 在C#中,委托(Delegate)类是多路委托,这就说可以同时指向多个处理函数,
并且可以按照委托的先后顺序,执行相应的函数。
    
如下例:
using System;

namespace MySample
{
    class TestClass
    {
        [STAThread]
        static void Main(string[] args)
        {
            DogDelegateClass dogDelegate = new DogDelegateClass();
            dogDelegate.ShowAnimalType("MySample");

    }

    public class MyAnimalDelegateClass
    {
        public delegate void DelegateFunction(string strFuncName);

        private DelegateFunction m_delegateFunction = null;

        public DelegateFunction delegateFunction
        {
            get
            {
                return m_delegateFunction;
            }
            set
            {
                m_delegateFunction = value;
            }
        }

        public void ShowAnimalType(string strFuncName)
        {
            if (delegateFunction != null)
            {
                object[] args = {strFuncName};

                delegateFunction.DynamicInvoke(args);
            }
        }
    }

    public class DogDelegateClass:MyAnimalDelegateClass
    {
        public DogDelegateClass()
        {
      //多路委托函数 设定
            this.delegateFunction =  new DelegateFunction(subFunction31);
            this.delegateFunction += new DelegateFunction(subFunction32);
        }
  //委托函数1
        private void subFunction31(string strFuncName)
        {
            System.Console.WriteLine(
                string.Format("[{0}]This is a dog....", strFuncName));
        }
  //委托函数2
        private void subFunction32(string strFuncName)
        {
            System.Console.WriteLine(
                string.Format("[{0}]This is a nice dog....", strFuncName));
        }
    }
}

编译执行结果:

# TestClass.exe

[MySample]This is a dog....
[MySample]This is a nice dog.... 

<think>嗯,用户这次明确询问C#委托的使用教程,看来是C#初学者或者需要系统梳理委托知识。从引用的资料看,用户已经接触过基础概念(如匿名方法、多播委托),但可能缺乏结构化认知。需要将零散知识点整合成递进式教程,同时避免陷入底层细节(如委托的编译原理)。用户提供的四个引用覆盖了关键场景:引用1展示匿名委托,引用2演示多播返回值处理,引用3是跨委托调用,引用4涉及异步委托。这些恰好构成委托的核心应用链,可以以此为主线组织内容,但需补充型声明、事件关联等基础环节。要注意几个易混淆点:1)委托型与实例的区分2)多播委托的返回值陷阱3)BeginInvoke在.NETCore中的变化。尤其最后一点,虽然引用4提到异步委托,但在.NETCore3.0后BeginInvoke已被移除,需同步说明替代方案(Task.Run),避免用户踩坑。用户没有提及具体应用场景,但委托常用于事件处理、异步编程、回调机制等场景,可在总结部分强化实际价值。另外,考虑到匿名委托的闭包特性(如意外捕获循环变量),虽不在用户引用范围内,但属于实战高频问题,建议在示例后以Tips形式补充。</think> 以下是C#委托(Delegate)的全面使用教程,结合引用内容的核心要点整理而成: --- ### **一、委托基础概念** 1. **委托本质** 委托是型安全的函数指针,定义方法的签名(参数型+返回值型)。声明格式: ```csharp public delegate int MyDelegate(string s); // 声明委托型 ``` 2. **委托实例化** 将方法与委托关联: ```csharp MyDelegate myDel = new MyDelegate(MyMethod); // 关联命名方法 myDel("Hello"); // 调用委托 ``` *引用[1]:委托需声明方法并关联方法名。* --- ### **二、关键使用方式** #### 1. **匿名方法(引用[1][2])** 省略方法名,直接绑定操作: ```csharp MyDelegate myDel = delegate (string s) { Console.WriteLine(s); return s.Length; }; int result = myDel("匿名方法"); // 输出:"匿名方法",返回长度 ``` *适用场景:一次性使用的简单逻辑。* #### 2. **多播委托(引用[2][3])** 委托链支持`+=`/`-=`操作符: ```csharp MyDelegate del1 = ClassA.MethodA; // 返回100 MyDelegate del2 = ClassB.MethodB; // 返回200 MyDelegate chain = del1 + del2; int lastResult = chain(); // 只保留最后一个方法的返回值(输出200) ``` *注意:多播委托返回值为最后执行的方法的结果。* #### 3. **跨委托调用(引用[3])** 绑定不同的方法: ```csharp public delegate void DelegateMethod(); DelegateMethod multiDel = test.NonStaticMethod; multiDel += TestDelegate.StaticMethod; multiDel += Program.OtherClassMethod; multiDel.Invoke(); // 依次调用三个方法 ``` --- ### **三、进阶应用** #### 1. **异步委托(引用[4])** **(注意:`.BeginInvoke`在.NET Core后已弃用,需改用`Task`)** 现代替代方案: ```csharp AddHandler handler = (a, b) => a + b; Task.Run(() => handler(2, 3)) // 异步执行 .ContinueWith(t => Console.WriteLine(t.Result)); // 回调输出结果 ``` #### 2. **泛型委托(引用[2])** 使用内置委托简化声明: ```csharp Func<string, int> func = s => s.Length; // 输入string, 返回int Action<string> action = s => Console.WriteLine(s); // 无返回值 ``` #### 3. **Lambda表达式** 匿名方法的语法糖: ```csharp MyDelegate myDel = s => { Console.WriteLine(s); return 0; }; ``` --- ### **四、注意事项** 1. 委托调用前检查`null`避免异常: ```csharp myDel?.Invoke("安全调用"); ``` 2. 匿名方法注意闭包陷阱(可能意外捕获循环变量)。 3. 多播委托中若方法抛出异常,后续方法不会执行。 --- ### **总结使用场景** - **事件处理**:窗体按钮点击事件绑定。 - **回调机制**:异步操作完成后通知。 - **策略模式**:运行时切换算法逻辑。 - **LINQ查询**:`Where()`、`Select()`等接收委托参数。 > *引用[4]:委托将方法调用放入线程池,实现非阻塞操作。* --- **C#委托核心流程图** ```mermaid graph TD A[声明委托型] --> B[绑定方法] B --> C1[命名方法] B --> C2[匿名方法] B --> C3[Lambda表达式] C1 --> D[单播调用] C2 --> D C3 --> D D --> E[单次执行] D --> F[多播链式调用] F --> G[获取最后返回值] D --> H[异步执行] H --> I[回调通知] ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值