Frequent interview questions: C# delegates (delegate, Action, Func, predicate) and events

Frequent interview questions: C# delegates (delegate, Action, Func, predicate) and events

When I first started working, I felt that commissions and events were a bit mysterious, but after you understood them, it seemed that it was not as difficult as imagined. This blog post can be regarded as my review and summary of commissions and events.

Two, entrust

The delegate in C# is equivalent to the pointer function in C++, but the delegate is object-oriented, safe, and is a special class. Of course, it is also a reference type, and the delegate passes a reference to the method.

2.1、delegate

To declare a delegate, you must use the keyword "delegate". The delegate is declared first and then instantiated. At least 0 parameters, at most 32 parameters

The format is as follows:

private delegate string GetAsString();

A delegate is a class, so its instantiation is the same as that of a class, except that it always accepts a constructor that takes the delegate method as a parameter. There are two ways to call a delegate method, as follows:

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

operation result:

image-20230723114808765

2.2、Action

Action is a generic delegate with no return value and can accept 0 to 16 incoming parameters

Action represents a delegate with no parameters and no return value

Action<int, string> indicates a delegate with incoming parameters int and string without return value

Action was used in [Implementation of Log4Net Logging] earlier. like:

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

The calling method is:

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

During operation, just run the content in the Action directly.

2.3、Func

Func is a generic delegate with a return value that can accept 0 to 16 incoming parameters

Func means a delegate with no parameters and return value of int

Func<object, string, int> indicates that the incoming parameter is object, and the return value of string is a delegate of int

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

calling method

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

operation result

oDaAmt9QDicSHv2w5zGuUnhPR5VU27JP1RuI6pHsmUjDB7O6oiaic18dL5OR6PDibbbKooePBsniappvuaaRpxcn6QQ

2.4、predicate

predicate is a generic delegate that returns bool and can only accept one incoming parameter

predicate means that the incoming parameter is an int and returns a bool delegate

Define a method:

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

Define the Predicate delegate

 Predicate<int> predicate = FindPoints;

transfer

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

operation result

oDaAmt9QDicSHv2w5zGuUnhPR5VU27JP1wZIms9F2kZibE0vfWGYjNc8uaicPY5ibECsrTWU52YovVEHEhDLlusCZA

2.5. Multicast delegation

The previous one only contains the invocation of one method, and the delegate can contain multiple methods. This kind of delegate is called a multicast delegate. Multicast delegates use two operators "+=" and "-+" to add and delete delegates.

First define two methods

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}");  
}

then call

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

operation result:

oDaAmt9QDicSHv2w5zGuUnhPR5VU27JP1YbOpyIiaW9FRgaoQZ3OOD7kTlILFqlKl6DNRiavyafZ2InbKm7ibNH3Kw

3. Events

Events are based on delegates, which provide a publish/subscribe mechanism for delegates, and event keywords need to be used to declare events.

Publisher: The publisher of an event, also known as the sender, is actually an object. This object will maintain its own state information by itself. When its own state information changes, it will trigger an event and notify some event subscribers;

Subscriber: Objects interested in events, also known as Receivers, can register interested events, and after the event publisher triggers an event, this code will be automatically executed

Do you feel familiar when you see sender? ! ! Don't be in a hurry, let's look at the declaration and use of the event

There is such an application scenario, if there is an abnormality in the system, the administrator needs to be notified in time. Then we need to add the function of notifying the administrator to our log records, but the question is, how to notify the administrator? At least not now. So we need to use events.

Add the code as follows, if you don’t know the log function, you can refer to [Log4Net log record implementation]

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

calling method

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

In the code that references the scene, first define a method to notify the administrator (here we directly Console.WriteLine out)

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

Register first, then trigger exception message

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

operation result

oDaAmt9QDicSHv2w5zGuUnhPR5VU27JP1oEH5iczqWCB3TDSviaDzoaiaLTnMr2r4HE14Acpp27eoib8v3H9htwYJOw

Here I just need to define the publisher, and you can subscribe in any way, isn't it very, very simple.

After understanding the above events, let's talk about the object sender and EventArgs e that often appear in .Net

Coding specification of .Net Framework:

1. The name of the delegate type should end with EventHandler

2. The prototype definition of the delegate: it has a void return value and accepts two input parameters: an Object type and an EventArgs type (or inherited from EventArgs)

3. The name of the event is the remaining part after the delegation removes the EventHandler

4. Types inherited from EventArgs should end with EventArgs

Now let's take a custom event for a new book release as an example

Create the corresponding class file:oDaAmt9QDicSHv2w5zGuUnhPR5VU27JP1BJWGMZSmCmyrh90B86rt7YRw6RNiasQKHlHIq9PM1K9Z9D5qP6Azn8Q

The eventer publishes the code:

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));  
    }  
}  

event subscriber

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}");  
    }  
}  

Event subscription and unsubscription

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");  

operation result

oDaAmt9QDicSHv2w5zGuUnhPR5VU27JP16I7NTMrvlQzO4E6OUiaJpKDXugetSeK6Is7pHgfiaDQtHjFHsl0aRRkw

After this example, we can know that the Object sender parameter represents the event publisher itself, and EventArgs e
is also the monitoring object. After in-depth understanding, do you feel that it is not as difficult as imagined.

Four. Summary

Here we talked about delegates and events. Using delegates and events in .Net development can reduce dependencies and layer coupling, and develop components with higher reusability.

Copyright statement: This article is collected or provided by netizens. If there is any infringement, please tell the moderator or leave a message, and this official account will be deleted immediately.

source:

https://www.cnblogs.com/snailblog/archive/2019/09/14/11520438.html

This article is published by mdnice multi-platform

Guess you like

Origin blog.csdn.net/qq_36799389/article/details/131879180