C#中的委托、匿名方法、Lambda、Action和Func

委托

委托概述

委托是存有对某个方法的引用的一种引用类型变量。定义方法的类型,可以把一个方法当作另一方法的参数。所有的委托(Delegate)都派生自 System.Delegate 类。委托声明决定了可由该委托引用的方法。

# 声明委托类型

委托类型声明与方法类似,可以理解为方法的类型,它与方法声明不同的地方:

  • 以delegate关键字开头
  • 没有方法主体
csharp 复制代码
delegate void ShowInfo();//可带参数,可不带参数

它不需要在类内部声明,因为它是类型声明,委托可指向一个与其具有相同标签的方法。

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    delegate void ShowInfo();
    public class Program
    {
        
        static void Main(string[] args)
        {
            ShowInfo showinfo = ShowInfo;//把签名赋值给委托变量
            showinfo?.Invoke();//调用委托,可指向相同标签的方法
        }
        static void ShowInfo()
        {
            Console.WriteLine("打印ShowInfo方法");
        }
    }
}

运行结果:

创建委托实例

法一

第一种是使用带new关键字进行创建,操作组成如下:

  • 委托类型名称
  • 一组圆括号,其中参数列表为成员的方法的名称,该方法可以是实例方法 也可以是静态方法
csharp 复制代码
MyDel delVar;//声明委托类型的变量
MyDel delVar= new MyDel(实例方法);//创建委托并保存引用
MyDel delVar= new MyDel(静态方法);//创建委托并保存引用

法二

可以使用快捷语法,仅由方法说明符组成,因为在方法名称和其相对应的委托类型之间存在隐式转换,可以理解为方法赋值给委托变量

csharp 复制代码
delVar = 实例方法;//创建委托并保存引用
delVar = 静态方法;//创建委托并保存引用

委托的调用

可以通过两种方式调用委托。一种是像调用方法一样调用委托 ,另外一种是使用委托的Invoke方法。

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    delegate void Show();

    public class Test
    {
        //静态方法
        public static void Print1()
        {
            Console.WriteLine("打印静态方法");
        }
        //实例方法
        public void Print2()
        {
            Console.WriteLine("打印实例方法");
        }

    }
    public class Program
    {
        
        static void Main(string[] args)
        {
            Test test = new Test();
            //1、调用方法一样调用委托
            Show show = test.Print2;//实例方法赋值给委托变量
            show();//调用委托
            Show show2 = Test.Print1;//静态方法赋值给委托变量
            show2();//调用委托


            //2、使用委托的Invoke方法
            show?.Invoke();//使用Invoke和空条件运算符
            show2?.Invoke();
        }

    }
}

委托的多播

委托对象可使用 "+" 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。"-" 运算符可用于从合并的委托中移除委托。

匿名方法

匿名方法提供了一种传递代码块作为委托参数的技术。匿名方法是没有名称只有主体的方法。在匿名方法中您不需要指定返回类型,它是从方法主体内的 return 语句推断的。

匿名方法表达式的语法包含如下组成部分:

  • delegate关键字
  • 参数列表,如果语句快没有使用任何参数则可以省略
  • 语句快,它包含了匿名方法的代码
csharp 复制代码
delegate ( 参数 ) {语句块};

案例

csharp 复制代码
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    delegate void Show();
    delegate int Add(int a, int b);
    public class Program
    {
        
        static void Main(string[] args)
        {
            //不带参数
            Show show = delegate
            {
                Console.WriteLine("打印匿名方法");
            };
            show();
            //带参数
            Add add = delegate(int a, int b)
            {
                int c = a + b;
                Console.WriteLine("和为多少:" + c);
                return c;
            };
            add(1,2);
            Console.ReadKey();

        }
    }
}

运行结果:

Lambda表达式

在匿名方法中,delegate关键字有点多余,因为编译器已经指定我们在将方法赋值给委托,因此我们可以利用Lambda表达式删除delegate关键字。在参数列表和匿名方法主体之间放置Lambda运算符=>。Lambda运算符读作"goes to"。如下代码演示这种转换。

csharp 复制代码
MyDel del = delegate(int x) {return x+1};//匿名方法
MyDel del = (int x) =>{return x+1};//Lambda表达式

上面看起来简洁,但是只省略6个字符,然后,编译器可以推断更多的信息,因此我们可以进一步简化。

  • 编译器可以从委托声明指定委托参数的类型,因此Lambda表达式可以省略参数的类型。如del1
    • 如果只有一个隐式类型参数还可以省略圆括号。如del2
  • Lambda表达式运行表达式的主体是语句块或表达式,如果语句块包含了返回语句,则可以省略return关键字。如del3
csharp 复制代码
MyDel del = delegate(int x) {return x+1};//匿名方法
MyDel del1 = (x) =>{return x+1};//Lambda表达式
MyDel del2 = x =>{return x+1};//Lambda表达式
MyDel del3 = x =>x+1;//Lambda表达式

Action 和Func

Action和Func都是.net内置的委托,可以使用他们以参数形式传递方法。他们都支持0-16个参数,然后Action没有返回值类型,Func有返回值类型,Func最后一个参数为返回值类型。

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{

    public class Program
    {
        
        static void Main(string[] args)
        {
            #region
            {
                //不带参数
                Action act1 = () => { Console.WriteLine("打印"); };
                act1();
                //带1个参数
                Action<int> act4 = a => { Console.WriteLine("a="+a); };//这里不能省略{}
                act4(2);


                //不带参数,带返回值
                Func<int> func1 = () => { return 1; };
                func1();

                //带1个参数,带带返回值
                Func<int, int> func2 = a => 
                {   
                    int b = a + 1;
                    Console.WriteLine("b=" + b);
                    return b;
                };
                func2(2);
            }
            #endregion
            Console.ReadKey();

        }

    }
}
相关推荐
黄金小码农17 分钟前
C# 2024/12/26 周四
c#
liuxin3344556620 分钟前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
码农W24 分钟前
QT--静态插件、动态插件
开发语言·qt
ke_wu1 小时前
结构型设计模式
开发语言·设计模式·组合模式·简单工厂模式·工厂方法模式·抽象工厂模式·装饰器模式
code04号1 小时前
python脚本:批量提取excel数据
开发语言·python·excel
小王爱吃月亮糖1 小时前
C++的23种设计模式
开发语言·c++·qt·算法·设计模式·ecmascript
hakesashou1 小时前
python如何打乱list
开发语言·python
网络风云2 小时前
【魅力golang】之-反射
开发语言·后端·golang
Want5952 小时前
Java圣诞树
开发语言·python·信息可视化
运维小文2 小时前
python之打印、变量、格式化输出
开发语言·python·python基础·hello world