Home  >  Article  >  Backend Development  >  Detailed explanation of delegate instance code in C# (picture and text)

Detailed explanation of delegate instance code in C# (picture and text)

黄舟
黄舟Original
2017-03-29 11:40:431625browse

This article mainly introduces the relevant knowledge of delegation in C#. It has a certain reference value. Let’s take a look at it with the editor.

Delegation is not a very easy thing to understand, but it is often used in work. You can see it everywhere, which is really surprising. It’s a love-hate feeling, and I believe many people have been troubled by it.

When it comes to delegation, if you have learned C language, you will immediately think of function pointers.

What is delegation? Delegates are typesafe in C# and can be subscribed to one or more function pointers with the same signature method. Delegation can pass functions as parameters, and its actual meaning is to let others act on your behalf. A delegate can be regarded as a pointer to a function. Integer can be pointed to by integer variable. Objectcan be pointed to by object variable.

Function You can also use a delegate variable to point to it. We can choose to think of the delegate type as an interface that defines only one method, and the instance of the delegate can be thought of as an object that implements that interface.

To use a delegate, four conditions must be met:

  • Declare the delegate type;

  • There must be a method that contains the required Code to be executed;

  • must create a delegate instance;

  • must invoke the delegate instance.

Declaration of delegation

Declaration method of delegation: delegate return value type delegate type name (parameter)

Delegated The declaration is basically the same as the declaration of the interface method, except that there is an additional delegate keyword in front of the return type keyword. Also, a delegate is generally declared as a public type because it can be called by others at any time.

The essence of delegation is also a type. We declare that a class can be instantiated, and a delegate can also be instantiated.

There are four types of delegation as follows:

//1.无参数无返回值
    public delegate void NoParaNoReturnEventHandler();
    //2.有参数无返回值
    public delegate void WithParaNoReturnEventHandler(string name);
    //3.无参数有返回值
    public delegate string NoParaWithReturnEventHandler();
    //4.有参数有返回值
    public delegate string WithParaWithReturnEventHandler(string name);

If the code wants to perform an operation but does not know the details of the operation, you can generally use delegation. For example, the only reason the Thread class knows what to run in a new thread is that it is provided with a ThreadStart or ParameterizedThreadStart delegate instance when starting the new thread.

Thread th = new Thread(Test);
th.Start();
public Thread(ThreadStart start);
public delegate void ThreadStart();

ThreadStart is a delegate with no parameters and no return value.

    static void Test()
    {
      Console.WriteLine("线程方法");
    }

The function signature of this Test method must be consistent with the function signature of the delegate ThreadStart.

Call of delegate

The delegate must be instantiated first and then called.

The signature of the function and the signature of the delegate must be consistent.

NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = ConsoleInfo;, The compiler helps us perform new, but it cannot be written as NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = ConsoleInfo();

because it becomes a function call.

#region 无返回值委托调用
    public static void Show()
    {
      //实例化委托
      NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = new NoParaNoReturnEventHandler(ConsoleInfo);
      //NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = ConsoleInfo; //简写
      //委托调用 通过Invoke()调用,或者可以直接省略
      _NoParaNoReturnEventHandler.Invoke();
      //_NoParaNoReturnEventHandler();
    }
    private static void ConsoleInfo()
    {
      Console.WriteLine("无参数无返回值的函数调用");
    } 
    #endregion

Without delegation, there is no asynchronous, and asynchronous is precisely because of the existence of delegation.

_NoParaNoReturnEventHandler.BeginInvoke(null,null); //Asynchronous call

Why use a delegate

We can call the method directly, why? Does it need to be called through a delegate? What’s the point of delegation?

Decoupled, closed to modifications, open to extensions. Logical separation.

You can understand a delegate as the parent class of a function, or a placeholder for a method.

Let's take a look at the code. Suppose there are two methods, one speaking English and one speaking Chinese, and the function signatures of these two methods are the same.

public static void SayChinese(string name)
    {
      Console.WriteLine("你好," + name);
    }
    public static void SayEnglish(string name)
    {
      Console.WriteLine("hello," + name);
    }

So when we call it externally,

  MyDelegate.SayChinese("张三");
  MyDelegate.SayEnglish("zhangsan");

If we want to call these two different methods, do we need to write different calling codes?

Can we just What about a method call? Modify the code as follows:

public static void Say(string name,WithParaNoReturnEventHandler handler)
    {
      handler(name);
    }
   public static void SayChinese(string name)
    {
      Console.WriteLine("你好," + name);
    }
    public static void SayEnglish(string name)
    {
      Console.WriteLine("hello," + name);
    }

In this way, only one method Say is called.

How to call it? The following three calling methods:

      WithParaNoReturnEventHandler _WithParaNoReturnEventHandler = new WithParaNoReturnEventHandler(MyDelegate.SayChinese);
      MyDelegate.Say("张三",_WithParaNoReturnEventHandler);
      MyDelegate.Say("张三", delegate(string name) { Console.WriteLine("你好," + name); }); //匿名方法
      MyDelegate.Say("张三", (name) => { Console.WriteLine("你好," + name); }); //lambda表达式

The above code uses several calling methods, and these calling methods are continuously optimized with the upgrade of C#. The first is the traditional calling method that existed in C# 1.0, and the second is the anonymous method calling method in C# 2.0. The so-called anonymous method is a method without a name. It is most appropriate to use anonymous methods when the method is only called once. But that's it. Lambda expressions in C#3. In fact, generic delegates are also supported, and .NET 3.5 goes a step further and introduces a set of generic delegate types called Func, which can obtain multiple parameters of a specified type and return another value of a specified type.

lambda expression

The essence of lambda expression is a method, an anonymous method.

If the method body has only one line and no return value, you can also remove the curly brackets and semicolons.

MyDelegate.Say("张三", (name) => Console.WriteLine("你好," + name));

如果方法体只有一行,有返回值,可以去掉大括号和return。

WithParaWithReturnEventHandler _WithParaWithReturnEventHandler = (name)=>name+",你好";

从.NET3.5开始,基本上不需要我们自己来申明委托了,因为系统有许多内置的委托。

Action和Func委托,分别有16个和17个重载。int表示输入参数,out代表返回值,out参数放置在最后。

Action表示无返回值的委托,Func表示有返回值的委托。因为方法从大的角度来分类,也分为有返回值的方法和无返回值的方法。

也就是说具体调用什么样的方法,完全由调用方决定了,就有了更大的灵活性和扩展性。为什么这么说,如果我有些时候要先说英语再说汉语,有些事时候要先说汉语再说英语,如果没有委托,我们会怎么样实现?请看如下代码:

public static void SayEnglishAndChinese(string name)
    {
      SayEnglish(name);
      SayChinese(name);
    }
    public static void SayChineseAndEnglish(string name)
    {
      SayChinese(name);
      SayEnglish(name);
    }

如果又突然要添加一种俄语呢?被调用方的代码又要修改,如此循环下去,是不是要抓狂了?随着不断添加新语种,代码会变得越来越复杂,越来越难以维护。这样的代码耦合性非常高,是不合理的,也就是出现了所谓的代码的坏味道,你可以通过设计模式(如观察者模式等),在不使用委托的情况下来重构代码,但是实现起来是非常麻烦的,要写很多更多的代码...

委托可以传递方法,而这些方法可以代表一系列的操作,这些操作都由调用方来决定,就很好扩展了,而且十分灵活。我们不会对已有的方法进行修改,而是只以添加方法的形式去进行扩展。

可能有人又会说,我直接在调用方那里来一个一个调用我要执行哪些方法一样可以实现这样的效果啊?

可你有没有想过,你要调用的是一系列方法,你根本无法复用这一系列的方法。使用委托就不一样了,它好比一个方法集合的容器,你可以往里面增减方法,可以复用的。而且使用委托,你可以延时方法列表的调用,还可以随时对方法列表进行增减。委托对方法进行了再一次的封装。

总结:也就是当你只能确定方法的函数签名,无法确定方法的具体执行时,为了能够更好的扩展,以类似于注入方法的形式来实现新增的功能,就能体现出委托的价值。

委托和直接调用函数的区别:用委托就可以指向任意的函数,哪怕是之前没定义的都可以,而不用受限于哪几种。

多播委托

组合的委托必须是同一个类型,其相当于创建了一个按照组合的顺序依次调用的新委托对象。委托的组合一般是给事件用的,用普通委托的时候很少用。

通过+来实现将方法添加到委托实例中,-来从委托实例中进行方法的移除。

+和-纯粹是为了简化代码而生的,实际上其调用的分别是Delegate.Combine方法和Delegate.Remove。

如果委托中存在多个带返回值的方法,那么调用委托的返回值是最后一个方法的返回值。

public static void MultipleShow()
    {
      //多播委托
      NoParaWithReturnEventHandler _NoParaWithReturnEventHandler = new NoParaWithReturnEventHandler(GetDateTime);
      _NoParaWithReturnEventHandler += GetDateTime;
      Console.WriteLine(_NoParaWithReturnEventHandler());
    }
    public static string GetDateTime()
    {
      return string.Format("今天是{0}号。", DateTime.Now.Day.ToString());
    }

委托总结:

  • 委托封装了包含特殊返回类型和一组参数的行为,类似包含单一方法的接口;

  • 委托类型声明中所描述的类型签名决定了哪个方法可用于创建委托实例,同时决定了调用的签名;

  • 为了创建委托实例,需要一个方法以及(对于实例方法来说)调用方法的目标;

  • 委托实例是不易变的,就像String一样;

  • 每个委托实例都包含一个调用列表——一个操作列表;

  • Events are not delegate instances - just paired add/remove methods (similar to the value method/assignment method of property).

Common usage scenarios: form value transfer, binding method when thread starts, lambda expression, asynchronous, etc.

Examples in life: Isn’t everyone grabbing train tickets now? Using the cloud to grab tickets is equivalent to using entrustment. You can buy the tickets directly by yourself, or you can host the tickets in the cloud to grab the tickets yourself. , when you are about to shoot, you must refresh at all times, enter the verification code when placing an order, etc. If you use the cloud to grab tickets, you only need to enter the ticket grabbing information in advance before releasing the tickets, and you no longer need to You're in charge, tickets will be issued automatically, and you don't need to know how Cloud Ticket Grabbing helps you grab tickets. The same time and train number can be made into a delegation instance, and many people use this delegation instance to grab tickets.

The above is the detailed content of Detailed explanation of delegate instance code in C# (picture and text). For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn