面试常考:C# 委托(delegate、Action、Func、predicate)和事件

这篇具有很好参考价值的文章主要介绍了面试常考:C# 委托(delegate、Action、Func、predicate)和事件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

面试常考:C# 委托(delegate、Action、Func、predicate)和事件

刚开始工作的时候,觉得委托和事件有些神秘,而当你理解他们之后,也觉得好像没有想象中的那么难,这篇博文算是自己对委托和事件的一次梳理和总结。

二、委托

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

2.1、delegate

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

格式如下所示:

private delegate string GetAsString();

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

int i = 10;  
var method = new GetAsString(i.ToString);  
//调用方法一  
Console.WriteLine($"method方法{method()}");  
//调用方法二  
Console.WriteLine($"method.Invoke方法{method.Invoke()}");  

运行结果:

2.2、Action

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

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

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

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

public static void Debug(string message, Action RegistedProperties)  
{  
	RegistedProperties();  
	log.Debug(message);  
}

调用方式为:

PFTLog.Debug("测试扩展字段", () => {  
    LogicalThreadContext.Properties["LogType"] = "扩展字段内容";  
});  

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

2.3、Func

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

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

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

public static decimal GetTotal(Func<int, int, decimal> func, int a, int b)  
{  
    return func(a, b);  
}  

调用方式

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

运行结果

2.4、predicate

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

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

定义一个方法:

public static bool FindPoints(int a)  
{  
    return a >= 60;  
}

定义Predicate委托

 Predicate<int> predicate = FindPoints;

调用

var points = new int[] {  
    10,  
    50,  
    60,  
    80,  
    100 };  
var result = Array.FindAll(points, predicate);  
Console.WriteLine($"结果为{string.Join(";", result)}");

运行结果

2.5、多播委托

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

先定义两个方法

public static void MultiplyByTwo(double v)  
{  
    double result = v * 2;  
    Console.WriteLine($"传值:{v};MultiplyByTwo结果为{result}");  
}  
public static void Square(double v)  
{  
    double result = v * v;  
    Console.WriteLine($"传值:{v};Square结果为{result}");  
}

然后调用

Action<double> operations = MultiplyByTwo;  
operations(1);  
operations += Square;  
operations(2);  

运行结果:

三、事件

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

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

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

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

有这样一个应用场景,如果系统有异常,需要及时的通知管理员。那么需要在我们的日志记录里面添加通知管理员的功能,但是问题来了,该怎么通知管理员呢?至少现在无法知道。所以我们就需要在使用到事件。

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

//声明一个通知的委托  
public delegate void NoticeEventHander(string message);  
//在委托的机制下我们建立以个通知事件  
public static event NoticeEventHander OnNotice;

调用方式

public static void Debug(string message, Action RegistedProperties)  
{  
    RegistedProperties();  
    log.Debug(message);  
    //执行通知  
    OnNotice?.Invoke($"系统异常,请及时处理,异常信息:{message}");  
}  

在引用场景的代码,先定义一个通知管理员的方法(这里我们直接Console.WriteLine出来)

public static void Notice(string message)  
{  
    Console.WriteLine($"通知内容为{message}");  
}

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

//注册方式一  
PFTLog.OnNotice += Notice;  
//注册方式二  
//PFTLog.OnNotice += new PFTLog.NoticeEventHander(Notice);  
  
PFTLog.Debug("测试扩展字段", () => {  
    LogicalThreadContext.Properties["LogType"] = "扩展字段内容";  
});  

运行结果

这里面我只需要定义好发布者,你可以以任何方式订阅,是不是很非常简单。

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

.Net Framework的编码规范:

一、委托类型的名称都应该以EventHandler结束

二、委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)

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

四、继承自EventArgs的类型应该以EventArgs结尾

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

创建对应的类文件:

事件者发布代码:

public class BookInfoEventArgs : EventArgs  
{  
    public BookInfoEventArgs(string bookName)  
    {  
        BookName = bookName;  
    }  
  
    public string BookName { get; set; }  
  
}    
public class BookDealer  
{  
    //泛型委托,定义了两个参数,一个是object sender,第二个是泛型 TEventArgs 的e  
    //简化了如下的定义  
    //public delegate void NewBookInfoEventHandler(object sender, BookInfoEventArgs e);  
    //public event NewBookInfoEventHandler NewBookInfo;  
    public event EventHandler<BookInfoEventArgs> NewBookInfo;  
    public void NewBook(string bookName)  
    {  
        RaiseNewBookInfo(bookName);  
    }  
  
    public void RaiseNewBookInfo(string bookName)  
    {  
        NewBookInfo?.Invoke(this, new BookInfoEventArgs(bookName));  
    }  
}  

事件订阅者

public class Consumer  
{  
    public Consumer(string name)  
    {  
        Name = name;  
    }  
  
    public string Name { get; set; }  
  
    public void NewBookHere(object sender, BookInfoEventArgs e)  
    {  
        Console.WriteLine($"用户:{Name},收到书名为:{ e.BookName}");  
    }  
}  

事件订阅和取消订阅

var dealer = new BookDealer();  
var consumer1 = new Consumer("用户A");  
dealer.NewBookInfo += consumer1.NewBookHere;  
dealer.NewBook("book112");  
var consumer2 = new Consumer("用户B");  
dealer.NewBookInfo += consumer2.NewBookHere;  
dealer.NewBook("book_abc");  
  
dealer.NewBookInfo -= consumer1.NewBookHere;  
dealer.NewBook("book_all");  

运行结果

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

四、总结

这里我们讲了委托和事件,在.Net开发中使用委托和事件,可以减少依赖性和层的耦合,开发出具有更高的重用性的组件。文章来源地址https://www.toymoban.com/news/detail-597171.html

到了这里,关于面试常考:C# 委托(delegate、Action、Func、predicate)和事件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • unity: C#的Action Event Delegate的异同

    目录 一、Action 二、Event 三、Action和Event区别: 四、Delegate 总结:Action Event Delegate的异同 前言: Action、Event和Delegate都是C#语言中的重要概念,分别用于管理函数指针,并且在某些情况下可以实现相同的目标。 Action是一种函数指针类型,它指向一个没有参数和返回值的函数。

    2024年02月12日
    浏览(39)
  • 【C#学习笔记】委托与事件 (从观察者模式看C#的委托与事件)

    转载请注明出处:🔗https://blog.csdn.net/weixin_44013533/article/details/134655722 作者:CSDN@|Ringleader| 主要参考: 委托(C# 编程指南) 事件介绍 C# 中的委托和事件简介 Delegate 类 Exploring the Observer Design Pattern微软技术文章翻译 委托是一种 引用类型 ,表示对具有特定参数列表和返回类型

    2024年02月04日
    浏览(49)
  • c# 事件与委托

    //在C#中, 事件是一种特殊的委托 ,它允许对象通知其他对象发生了某个特定的事件。 //事件通常用于GUI应用程序中,例如当用户单击按钮时,按钮控件会引发Click事件, //然后其他对象可以订阅该事件并执行相应的操作。 //以下是一个简单的示例,演示如何在C#中使用事件和

    2024年02月06日
    浏览(41)
  • C#委托和事件简单复习

    太久没用了,简单的复习一下 快速过一遍语法使用 1.定义一个委托类型 只需要在声明的前面加上delegate,其他的就跟声明一个方法(函数)类似 2.使用刚刚声明的委托 需要定义一个返回值跟参数与我们刚刚定义的委托一致 3.然后声明一个SayHello类型(委托)的变量 把

    2024年02月14日
    浏览(45)
  • 委托与事件(一)——C#版本

      委托是对 函数的封装 ,可以当作给方法的特征指定一个名称。而事件则是 委托的一种特殊形式 ,当发生有意义的事情时,事件对象处理通知过程。   委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有 完全相同的行为 。   用例子来说明为

    2023年04月09日
    浏览(45)
  • C#学习,委托,事件,泛型,匿名方法

    目录 委托 声明委托 实例化委托 委托的多播 委托的用途 事件 通过事件使用委托 声明事件 泛型 泛型的特性 泛型方法 泛型的委托 匿名方法 编写匿名方法的语法 类似于指针,委托是存有对某个方法的引用的一种引用类型变量,引用可以在运行时被改变。特别用于实现事件和

    2024年02月12日
    浏览(46)
  • C# 中的委托和事件机制

    在C#中,委托和事件是非常重要的概念,用于实现程序中的回调和事件处理。在这里,我们将介绍C#中委托和事件机制的基础知识和用法。 委托是一种类似于C/C++函数指针的概念,它允许将方法作为参数传递到其他方法中,以实现回调函数的功能。委托是一种类型,它可以表示

    2023年04月21日
    浏览(36)
  • C#学习笔记8:接口、委托、事件

    今日继续我的C#学习之路,今日学习接口、委托、事件,文章从实践出发学习这三个设计理念,并提供完整源码 目录 1、接口(多重继承): 代码: 运行结果: 2、委托(方法的代理/函数指针): 创建控制台程序实现委托: 遇到的报错及解决: 修改后的代码: 运行结果: 3、

    2024年04月15日
    浏览(54)
  • C# 事件和委托的区别并说明

    事件是基于委托的,为委托提供了一个发布/订阅机制。可以说事件是一种特殊的委托,他的调用和委托是一样的。 事件的声明 public event 委托类型 事件名称 通常事件的命名以事件名称+Event来命名。如public event delegate NotifyEvent; 事件和委托的区别如下: 事件只能在方法的外部

    2024年02月07日
    浏览(39)
  • C# 一个完整的委托、事件学习示例

    该示例符合委托、事件的定义规则,并且可以帮助大家更好地理解委托和事件的使用! 先定义了一个名为 MyEventArgs 的类,继承自 EventArgs ,它包含一个 Message 属性,用于存储传递的消息。 Publisher 类中添加了一个 protected virtual 的方法 OnMyEvent ,用于触发 MyEvent 事件,并传递

    2024年02月07日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包