C# 用委托有什么好处? 它起什么作用?

什么是委托  

首先要知道什么是委托,用最通俗易懂的话来讲,你就可以把委托看成是用来执行方法(函数)的一个东西。

(1) 从数据结构来讲,委托是和类一样是一种用户自定义类型

 (2) 从设计模式来讲,委托(类)提供了方法(对象)的抽象。

既然委托是一种类型,那么它存储的是什么数据?

我们知道,委托是方法的抽象,它存储的就是一系列具有相同签名和返回回类型的方法的地址。调用委托的时候,委托包含的所有方法将被执行。

如何使用委托  

在使用委托的时候,你可以像对待一个类一样对待它。即先声明,再实例化。只是有点不同,类在实例化之后叫对象或实例,但委托在实例化后仍叫委托。如下:

1    namespace Vczx.ProCSharp.Exc
2    {
3        delegate double MathsOp( double x );
4        //class defination here
5    }

  这就声明了一个委托

       意义:任何一个返回值为double,且只有一个形参为double的函数,都可以用这个委托来调用。
  注意:

  1. 需求情况而定,一般定义在与类定义平级部分,且用public修饰,便于外部的调用。

  2. 若定义于类的内部,则必须通过调用该类的成员才能取得其委托的引用,在频繁的调用该委托的情况下,就不是很适合。

  实例化:
  首先我们要先有一个满足委托声明的方法,假设一个返回一个数的2倍的方法:

1class MathsOperations
2{
3    public static double MultiplyBy2( double value )
4    {
5        return value * 2;
6    }
7}

  有了这样一个方法,我们就可以实例化一个委托了:

MathsOp operation = new MathsOp( MathsOperations.MultiplyBy2 );

  在实例化一个委托时,要给它一个参数,这个参数就是委托执行的方法,它可以是静态方法,也可以是实例方法(这一点有别于函数指针,函数指针只能调用静态方法),如:

MathsOp operation = new MathsOp( new Class1().Method1 );

在实例化完一个委托之后,就可以用这个委托来调用方法了:

double result = operation( 1.23 );

例子代码:

复制代码
1   namespace Vczx.ProCSharp.Exc
2   {  
3     delegate double MathsOp( double x );
4     class Start
5     {
6        public class MyDelegate
7        {
8            public static double MultiplyBy2( double x )
9            {
10                return x * 2;
11            }
12        }
13        [STAThread]
14        static void Main(string[] args)
15        {
16            MathsOp operation = new MathsOp( MyDelegate.MultiplyBy2 );
17            double x = 1.23;
18            double result = operation( x );
19            Console.WriteLine( “{0} multiply by 2 is {1}”, x, result ); 
20            Console.Read();
21        }
22     }
23   }
复制代码

多路广播委托
   前面使用的委托只包含一个方法调用。调用委托的次数与调用方法的次数相同。如果要调用多个方法,就需要多次显示调用这个委托。其实委托也可以包含多个方法,这种委托就是多路广播委托。多路广播委托派生于System.MulticastDelegate,它的Combine方法允许把多个方法调用链接在一起,我们可以通过+=来向委托添加调用方法,也可以用-=删除其中的调用方法。如:

复制代码
1   namespace Vczx.ProCSharp.Exc
2   {
3      public class MyDelegate
4      {
5         public static void MultiplyBy2( double value )
6        {
7            double result =  value * 2;
8            Console.WriteLine( “Multiplying by 2: {0} gives {1}”, value, result );
9        }
10
11        public static void Squre( double value )
12        {
13            double result = value * value;
14            Console.WriteLine( “Squaring: {0} gives {1}”, value, result );
15        }
16      }
17
18      delegate void MathsOp( double x );
19
20    class Start
21    {
22        [STAThread]
23        static void Main(string[] args)
24        {
25            MathsOp operation = new MathsOp( MyDelegate.MultiplyBy2 );
26            operation += new MathsOp( MyDelegate.Squre );
27            double x = 1.23;
28            operation( x );
29
30            operation -= new MathsOp( MyDelegate.MultiplyBy2 );
31            operation( x );
32            
33            Console.Read();
34         }
35     }
36   }
复制代码

输出:
Multiplying by 2: 1.23 gives 2.46
Squaring: 1.23 gives 1.5129
Squaring: 1.23 gives 1.5129
  注意,多路广播委托声明时必须返回void,否则返回值不知道应该送回什么地方。对此,我做了一个测试:如果不将委托的声明返回void,则返回值返回的是最后一个链入委托链的方法的返回值,编译不会出错。
为什么要用委托
  使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时知道将调用哪个方法。与C或C++中的函数指针不同,委托是面向对象,而且是类型安全的

补充

委托调用跟方法调用类似。委托调用后,调用列表的每个方法将会被执行。

在调用委托前,应判断委托是否为空。调用空委托会抛出异常。

if(null != del)
{
     del();//委托调用
}

匿名方法

匿名方法是在初始化委托时内联声明的方法。

基本结构:

deleage( 参数 ) { 语句块 }

例如:


delegate int MyDel (int x); //定义一个委托 

MyDel del = delegate( int x){ return x; };

从上面我们可以看到,匿名方法是不会显示声明返回值的

 Lambda表达式

Lambda表达式主要用来简化匿名方法的语法。在匿名方法中,delegate关键字有点多余,因为编译器已经知道我们将方法赋值给委托。通过几个简单步骤,我们就可以将匿名方法转换为Lambda表达式:

  • 删除delegate关键字
  • 在参数列表和匿名方法主体之间防Lambda运算符=>。Lambda运算符读作"goes to"。
MyDel del = delegate( int x) { return x; };//匿名方法
MyDel del2 = (int x) => {return x;};//Lambda表达式
MyDel del3 = x => {return x};//简写的Lambda表达式

 Action和Func

1.Action说明

Action是.NET Framework内置的泛型委托,可以使用Action委托以参数形式传递方法,而不用显示声明自定义的委托。封装的方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有一个通过值传递给它的参数,并且不能有返回值。

2.Action 的特点

3.例子

复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ActionDemo : MonoBehaviour
{

    Action  action;//表示无参
    Action<int> action1;//表示有传入参数int
    void Start()
    {
        action = actionH1;//没有参数
        action();

        action1 = actionH2;//一个 int参数 
        action1(456);

        actionH3(() => { Debug.Log("执行完actionH3了"); });//lambda 表达式 来执行委托

        actionH3(actionH4);//执行完 actionH3后回调 actionH4方法
    }

    private void actionH1()//没有参数
    {
        Debug.Log(123);
    }
    private void actionH2(int index)//参数int
    {
        Debug.Log(index);
    }
    private void actionH3(Action act)//参数 Action
    {
        Debug.Log("在执行actionH3");
        act();//回调 这个 委托方法
    }
    private void actionH4()//执行完 actionH3后的回调执行
    {
        Debug.Log("执行完actionH3了");
    }
}
复制代码

delegate 和 Action 写法对比

delegate 写法

复制代码
 public delegate void CommonDelegate(string str);//定义委托
    void Start()
    {
        CommonDelegate common = Init;//实例化委托
        common("hello world");//执行
    }
    private void Init(string str)//放发
    {
        Debug.Log(str);//打印
    }
复制代码

 修改为Action 写法

复制代码
    void Start()
    {
        Action<string> act = Init;
        act("hello world");
    }
    private void Init(string str)//放发
    {
        Debug.Log(str);//打印
    }
复制代码

Action 代码更简洁点

Func

Func和Action相同点 :

 

 

Func的返回值

Func< T1 > (有返回值)------无参数类型,T1为返回值类型

Func<T1,T2>(有返回值)------T1为0-16个参数类型,T2为返回值类型

Func<T1,T2,T3>(有返回值)------T1和T2为0-16个参数类型,T3为返回值类型

也就是说 参数最后一位就是返回值类型(返回值的类型和Func输出参数类型相同)
Func<int【参数类型】,……,bool【最后一个是返回值类型】】> func

复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FuncDemo : MonoBehaviour
{

    /*
       Func<参数.....> //参数最后一位就是 委托的 返回类型
     
     */

    void Start()
    {
        Func<string> MyFun1 = MyMethodA;//这样定义 就是 无参的Func 返回一个string  
        Debug.Log(MyFun1());//执行 这个委托

        Func<string,string> MyFun2 = MyMethodB;//这样定义 就是参数为string的Func 返回一个string值  
        Debug.Log(MyFun2("一个参数"));//执行 这个委托

        //一次类推 
        Func<string, string,bool> MyFun3 = MyMethodC;//这样定义 就是2个参数为string的Func 返回一个bool值  
        Debug.Log(MyFun3("一个参数","二个参数"));//执行 这个委托
    }

    //无参 返回string
    private string MyMethodA()
    {
        return "MyMethodA-->  hello world";
    }

    //一个string参数 +返回值string值
    private string MyMethodB(string arg)
    {
        return "MyMethodB-->  hello world  " + arg;
    }
    //两个string参数 +返回bool值
    private bool MyMethodC(string arg1, string arg2)
    {
        Debug.Log("MyMethodC-->  hello world  " + arg1 + "   " + arg2);
        return true;
    }
}
复制代码

运行结果

 

 简单的来说
有返回值就用Func,无返回值就用Action

原文链接:https://blog.csdn.net/qq_39984000/article/details/115245134

原文:https://www.cnblogs.com/asdyzh/p/9846206.html

posted @   Zhongxingxing  阅读(662)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示