C#中的delegate、event、action及匿名函数(lambda表达式)

1、委托(Delegate)

这块基本来自C# 委托(Delegate) | 菜鸟教程

参考https://www.cnblogs.com/digital-college/p/17282032.html

委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。个人认为委托的主要意义就是能让调用的方法变量化,在其他方法里传递,类似于函数指针

public delegate void printString(string s);
...//上面的委托可被用于引用任何一个带有一个单一的 string 参数的方法,并返回一个 int 类型变量。
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);

委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签(即参数类型和返回类型一样)的方法。

一旦声明了委托类型,委托对象必须使用 new 关键字来创建,且与一个特定的方法有关。当创建委托时,传递到 new 语句的参数就像方法调用一样书写,但是不带有参数

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

使用委托的这个有用的特点,您可以创建一个委托被调用时要调用的方法的调用列表。这被称为委托的 多播(multicasting),也叫组播。

//定义一个委托
        public delegate void MyDelegate1(int x);

        public static void Method1(int a)
        {
            Console.WriteLine($"a={a}");
        }

        public static void Method2(int b)
        {
            Console.WriteLine($"b={b}");
        }

        static void Main(string[] args)
        {
            MyDelegate1 md = new MyDelegate1(Method1);
            md += Method2;
            md(35);

            Console.ReadLine();
        }

但是委托有一个弊端,它可以使用“=”将所有已经订阅的取消,只保留=后的这一个订阅。由此引出了event类型

2、事件(event)

大部分来自https://www.cnblogs.com/digital-college/p/17282032.html

事件event是一种特殊的委托实例,在定义类外它只能+=,-=,不能直接用=及其他的函数。事件常用来实现发布-订阅模式。

    //定义一个委托
        public delegate void MyDelegate1(int x);
        //定义一个事件
        public event MyDelegate1 emd;

经过长久的经验积累后,人们发现,绝大多数事件的委托的定义,是用public delegate void XXX(object sender, EventArgs e);这样一个委托原型进行定义的(括号里是参数),是一件重复性的工作,于是,EventHandler应运而生。它的出现就是为了避免这种重复性工作,并建议尽量使用该类型作为事件的原型。使用EventHandler时可以不用定义委托 。

public class Demo
        {
            public event EventHandler emd;
            public void RaiseEvent()
            {
                emd?.Invoke(this, EventArgs.Empty);//只能在定义类调用
            }
        }

        static void Main(string[] args)
        {
            var instance = new Demo();
            instance.emd += (sender, arg) =>
            {
                Console.WriteLine("执行事件1!");
            };//匿名函数

            instance.emd += (sender, arg) =>
            {
                Console.WriteLine("执行事件2!");
            };

            instance.RaiseEvent();

            Console.ReadLine();
        }

注意里面的sender、arg是参数名,不是参数类型,参数类型事件里已经定义好了。同时,我们也可以看出:事件是按照+=的订阅先后顺序执行的。

除此以外还可以继承EventArgs类进行一些变形

public class ScoreEventArgs : EventArgs
{
    public int Score { get; }
    public ScoreEventArgs(int score) { Score = score; }// 只读属性的值在对象初始化期间(即在构造函数中)是可以被设置的。
}

public class Game
{
    public event EventHandler<ScoreEventArgs> OnScoreChanged;

    public void ChangeScore(int newScore)
    {
        OnScoreChanged?.Invoke(this, new ScoreEventArgs(newScore));
    }
}

3、Func与Action

大部分来自https://www.cnblogs.com/digital-college/p/17282032.html

在委托delegate出现了很久以后,微软的.NET设计者们终于领悟到,其实所有的委托定义都可以归纳并简化成只用Func与Action这两个语法来表示。它们都是两种预定义的委托类型。其中,Func代表有返回值的委托,Action代表无返回值的委托。有了它们两,我们以后就不再需要用关键字delegate来定义委托了。这里也再次说明委托的意义是将方法变量化

同时,若再用lambda表达式取代被委托指向的具体方法,则整个委托的“定义+赋值”两步将大大简化(lambda表达式本来也是方法定义的一种简化形式)。

1)使用委托

// 定义一个接受两个int参数并返回int的委托类型
public delegate int MyDelegate(int x, int y);

// 使用委托
MyDelegate add = (a, b) => a + b;
int result = add(2, 3); // result = 5

2)使用Func 

// 定义一个接受两个int参数并返回int的Func委托
Func<int, int, int> add = (a, b) => a + b;
int result = add(2, 3); // result = 5

这个例子没有体现出委托的可变性,来看下一个 

//定义一个方法再把方法赋给Func委托
public static int Test(int a,int b)
        {
            return a+b;
        }
Func<int, int, int> md=Test;
int result = md(2,3);       

 3)使用Action(Action更像是一种泛型事件)

public class Game
{
    public Action<int> OnScoreChanged;

    public void ChangeScore(int newScore)
    {
        OnScoreChanged?.Invoke(newScore);
    }
}

匿名函数待补充

  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值