马上加入IBC程序猿 各种哪里能玩开元棋牌_彩票开元棋牌app_开元棋牌有麻将吗?随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序哪里能玩开元棋牌_彩票开元棋牌app_开元棋牌有麻将吗?享受不尽 C#问题入口 ASP.NET问题入口

【C#问题提交】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接毕业设计】 面试-葵花宝典下载

官方一群:

官方二群:
查看: 22|回复: 0
打印 上一主题 下一主题

C#委托(delegate、Action、Func、predicate)和事件

[复制链接]
  • TA的每日心情
    开心
    3?天前
  • 签到天数: 1476 天

    [LV.10]以坛为家III

    1364

    主题

    3269

    帖子

    9万

    积分

    管理员

    IBC编程社区-原道楠

    Rank: 9Rank: 9Rank: 9

    积分
    94944

    推广达人突出贡献优秀版主荣誉管理论坛元老

    跳转到指定楼层
    楼主
    发表于 2019-9-17 11:34:51 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

    马上加入IBC,查看更多教程

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x

    一、媒介

    刚开始工作的时间,觉得委托和事件有些神秘,而当你理解他们之后,也觉得似乎没有想象中的那么难。在项目中运用委托和事件,你会发现他非常棒,这篇博文算是自己对委托和事件的一次梳理和总结。

    二、委托

    C#中的委托,相称于C++中的指针函数,但委托是面向对象的,是安全的,是一个特殊的类,当然他也是引用类型,委托传递的是对方法的引用。

    2.1、delegate

    声明委托就必须使用关键字“delegate”,委托是先声明,后实例化。至少0个参数,至多32个参数

    格式如下所示:

    1. private delegate string GetAsString();
    复制代码

    委托是一个类,以是他的实例化跟类的实例化一样,只是他总是担当一个将委托方法作为参数的构造函数。调用委托方法就有两种方式,如下所示:

    1. int i = 10;
    2. var method = new GetAsString(i.ToString);
    3. //调用方法一
    4. Console.WriteLine($"method方法{method()}");
    5. //调用方法二
    6. Console.WriteLine($"method.Invoke方法{method.Invoke()}");
    复制代码

    运行效果:

    2.2、Action

    Action是无返回值的泛型委托,可以担当0个至16个传入参数

    Action 表示无参,无返回值的委托

    Action 表示有传入参数int,string无返回值的委托

    前面我们【Log4Net 日记记录的实现】中,就使用了Action。如:

    1. public static void Debug(string message, Action RegistedProperties)
    2. {
    3. RegistedProperties();
    4. log.Debug(message);
    5. }
    复制代码

    调用方式为:

    1. PFTLog.Debug("测试扩展字段", () => {
    2. LogicalThreadContext.Properties["LogType"] = "扩展字段内容";
    3. });
    复制代码

    在运行中,直接运行Action中的内容即可。

    2.3、Func

    Func是有返回值的泛型委托,可以担当0个至16个传入参数

    Func 表示无参,返回值为int的委托

    Func 表示传入参数为object, string 返回值为int的委托

    1. public static decimal GetTotal(Func func, int a, int b)
    2. {
    3. return func(a, b);
    4. }
    复制代码

    调用方式

    1. var total = GetTotal((a, b) => { return (decimal)a + b; }, 1, 2);
    2. Console.WriteLine($"效果为{total}");
    复制代码

    运行效果

    2.4、predicate

    predicate 是返回bool型的泛型委托,只能担当一个传入参数

    predicate 表示传入参数为int 返回bool的委托

    界说一个方法:

    1. public static bool FindPoints(int a)
    2. {
    3. return a >= 60;
    4. }
    复制代码

    界说Predicate委托

    1. Predicate predicate = FindPoints;
    复制代码

    调用

    1. var points = new int[] {
    2. 10,
    3. 50,
    4. 60,
    5. 80,
    6. 100 };
    7. var result = Array.FindAll(points, predicate);
    8. Console.WriteLine($"效果为{string.Join(";", result)}");
    复制代码

    运行效果

    2.5、多播委托

    前面的只包含了一个方法的调用,委托可以包含多个方法,这种委托就叫做多播委托。多播委托利用“+=”和“-+”两种运算符举行添加和删除委托。

    先界说两个方法

    1. public static void MultiplyByTwo(double v)
    2. {
    3. double result = v * 2;
    4. Console.WriteLine($"传值:{v};MultiplyByTwo效果为{result}");
    5. }
    6. public static void Square(double v)
    7. {
    8. double result = v * v;
    9. Console.WriteLine($"传值:{v};Square效果为{result}");
    10. }
    复制代码

    然后调用

    1. Action operations = MultiplyByTwo;
    2. operations(1);
    3. operations += Square;
    4. operations(2);
    复制代码

    运行效果:

    三、事件

    事件是基于委托,为委托提供一种发布/订阅机制,声明事件须要使用event关键字。

    发布者(Publisher):一个事件的发行者,也称作是发送者(sender),实在就是个对象,这个对象会自行维护自己的状态信息,当自己状态信息变动时,便触发一个事件,并关照说有的事件订阅者;

    订阅者(Subscriber):对事件感兴趣的对象,也称为Receiver,可以注册感兴趣的事件,在事件发行者触发一个事件后,会主动实行这段代码

    是不是看到sender,就有种很认识的感觉!!!先不忙着急,我们先看下事件的声明和使用

    有这样一个应用场景,假如系统有异常,须要实时的关照管理员。那么须要在我们的日记记录内里添加关照管理员的功能,但是题目来了,该怎么关照管理员呢?至少现在无法知道。以是我们就须要在使用到事件。

    添加代码如下,假如不知道日记功能的可以参考【Log4Net 日记记录的实现】

    1. //声明一个关照的委托
    2. public delegate void NoticeEventHander(string message);
    3. //在委托的机制下我们建立以个关照事件
    4. public static event NoticeEventHander OnNotice;
    复制代码

    调用方式

    1. public static void Debug(string message, Action RegistedProperties)
    2. {
    3. RegistedProperties();
    4. log.Debug(message);
    5. //实行关照
    6. OnNotice?.Invoke($"系统异常,请实时处理处罚,异常信息:{message}");
    7. }
    复制代码

    在引用场景的代码,先界说一个关照管理员的方法(这里我们直接Console.WriteLine出来)

    1. public static void Notice(string message)
    2. {
    3. Console.WriteLine($"关照内容为{message}");
    4. }
    复制代码

    先注册,然后触发异常消息

    1. //注册方式一
    2. PFTLog.OnNotice += Notice;
    3. //注册方式二
    4. //PFTLog.OnNotice += new PFTLog.NoticeEventHander(Notice);
    5. PFTLog.Debug("测试扩展字段", () => {
    6. LogicalThreadContext.Properties["LogType"] = "扩展字段内容";
    7. });
    复制代码

    运行效果

    这内里我只须要界说好发布者,你可以以任何方式订阅,是不是很非常简单。

    弄明白了上面的事件,我们在来说说.Net经常出现的object sender和EventArgs e

    .Net Framework的编码规范:

    一、委托类型的名称都应该以EventHandler竣事

    二、委托的原型界说:有一个void返回值,并担当两个输入参数:一个Object 类型,一个 EventArgs类型(或继续自EventArgs)

    三、事件的定名为 委托去掉 EventHandler之后剩余的部门

    四、继续自EventArgs的类型应该以EventArgs末端

    现在我们以一个新书发布的自界说事件为例

    创建对应的类文件:

    事件者发布代码:

    1. public class BookInfoEventArgs : EventArgs
    2. {
    3. public BookInfoEventArgs(string bookName)
    4. {
    5. BookName = bookName;
    6. }
    7. public string BookName { get; set; }
    8. }
    复制代码
    1. public class BookDealer
    2. {
    3. //泛型委托,界说了两个参数,一个是object sender,第二个是泛型 TEventArgs 的e
    4. //简化了如下的界说
    5. //public delegate void NewBookInfoEventHandler(object sender, BookInfoEventArgs e);
    6. //public event NewBookInfoEventHandler NewBookInfo;
    7. public event EventHandler NewBookInfo;
    8. public void NewBook(string bookName)
    9. {
    10. RaiseNewBookInfo(bookName);
    11. }
    12. public void RaiseNewBookInfo(string bookName)
    13. {
    14. NewBookInfo?.Invoke(this, new BookInfoEventArgs(bookName));
    15. }
    16. }
    复制代码

    事件订阅者

    1. public class Consumer
    2. {
    3. public Consumer(string name)
    4. {
    5. Name = name;
    6. }
    7. public string Name { get; set; }
    8. public void NewBookHere(object sender, BookInfoEventArgs e)
    9. {
    10. Console.WriteLine($"用户:{Name},收到书名为:{ e.BookName}");
    11. }
    12. }
    复制代码

    事件订阅和取消订阅

    1. var dealer = new BookDealer();
    2. var consumer1 = new Consumer("用户A");
    3. dealer.NewBookInfo += consumer1.NewBookHere;
    4. dealer.NewBook("book112");
    5. var consumer2 = new Consumer("用户B");
    6. dealer.NewBookInfo += consumer2.NewBookHere;
    7. dealer.NewBook("book_abc");
    8. dealer.NewBookInfo -= consumer1.NewBookHere;
    9. dealer.NewBook("book_all");
    复制代码

    运行效果

    颠末这个例子,我们可以知道Object sender参数代表的是事件发布者自己,而EventArgs e 也就是监督对象了。深入理解之后,是不是觉得也没有想象中的那么难了。

    四、总结

    这里我们讲了委托和事件,在.Net开辟中使用委托和事件,可以淘汰依靠性和层的耦合,开辟出具有更高的重用性的组件。







    来源:https://www.cnblogs.com/snailblog/archive/2019/09/14/11520438.html
    C#论坛 www.ibcibc.com IBC编程社区
    C#
    C#论坛
    IBC编程社区
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则