Maison  >  Article  >  développement back-end  >  Explication détaillée du code d'instance de délégué en C# (image et texte)

Explication détaillée du code d'instance de délégué en C# (image et texte)

黄舟
黄舟original
2017-03-29 11:40:431625parcourir

Cet article présente principalement les connaissances pertinentes sur la délégation en C#. Elle a une certaine valeur de référence, regardons-la avec l'éditeur ci-dessous

La délégation n'est pas très simple à comprendre, mais elle est souvent utilisée dans le travail, on la voit partout, ce qui est vraiment surprenant. C'est un sentiment d'amour-haine, et je crois que beaucoup de gens en ont été troublés.

En matière de délégation, si vous avez appris le langage C, vous penserez immédiatement au pointeur de fonction.

Qu'est-ce que la délégation ? Les délégués sont de typesafe en C# et peuvent être abonnés à un ou plusieurs pointeurs de fonction avec la même méthode de signature. La délégation peut transmettre des fonctions en tant que paramètres, et sa véritable signification est de laisser les autres agir en votre nom. Un délégué peut être considéré comme un pointeur vers une fonction. Integer peut être pointé par un entiervariable, Object peut être pointé par une variable d'objet et

Object

peut être pointé vers une variable d'objet. 🎜>fonction Vous pouvez également utiliser une variable déléguée pour pointer vers elle. Nous pouvons choisir de considérer le type délégué comme une interface

qui ne définit qu'une seule méthode, et l'instance déléguée peut être considérée comme un objet qui implémente cette interface.

Pour utiliser un délégué, 4 conditions doivent être remplies :
  • Déclarer le type de délégué
  • Il doit y avoir un méthode qui contient le code requis à exécuter ;
  • doit créer une instance de délégué
  • doit invoquer (invoquer) l'instance de délégué ;

Déclaration de délégation

Méthode de déclaration de délégation : type de valeur de retour du délégué nom du type de délégué (paramètre)

délégué Le La déclaration est fondamentalement la même que la déclaration de la méthode d'interface, sauf qu'il y a un mot-clé délégué supplémentaire devant le mot-clé de type retour. De plus, un délégué est généralement déclaré comme étant de type public car il peut être appelé par d'autres à tout moment.

L'essence de la délégation est aussi un type. Nous déclarons qu'une classe peut être instanciée et qu'un délégué peut également être instancié.

Il existe quatre types de délégués comme suit :
//1.无参数无返回值
    public delegate void NoParaNoReturnEventHandler();
    //2.有参数无返回值
    public delegate void WithParaNoReturnEventHandler(string name);
    //3.无参数有返回值
    public delegate string NoParaWithReturnEventHandler();
    //4.有参数有返回值
    public delegate string WithParaWithReturnEventHandler(string name);

Si le code souhaite effectuer une opération mais ne connaît pas les détails de l'opération, vous pouvez généralement utiliser des délégués. Par exemple, la seule raison pour laquelle la classe Thread sait quoi exécuter dans un nouveau thread est qu'elle reçoit une instance déléguée ThreadStart ou ParameterizedThreadStart lors du démarrage du nouveau thread.
Thread th = new Thread(Test);
th.Start();
public Thread(ThreadStart start);
public delegate void ThreadStart();

ThreadStart est un délégué sans paramètres ni valeur de retour.
    static void Test()
    {
      Console.WriteLine("线程方法");
    }

La signature de fonction de cette méthode Test doit être cohérente avec la signature de fonction du délégué ThreadStart.

Appel du délégué

Il faut d'abord instancier le délégué, puis l'appeler.

La signature de la fonction et la signature du délégué doivent être cohérentes. NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = ConsoleInfo;, Le compilateur nous aide à effectuer de nouvelles choses, mais il ne peut pas être écrit comme NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = ConsoleInfo();

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

Sans délégation, il n'y aurait pas d'asynchrone, et l'asynchrone est précisément dû à l'existence de la délégation.

_NoParaNoReturnEventHandler.BeginInvoke(null,null); //Appel asynchrone

Pourquoi utiliser un délégué

On peut appeler la méthode directement, pourquoi ? Doit-il être convoqué par l’intermédiaire d’un délégué ? Que signifie délégation ?

Découplé, fermé aux modifications, ouvert aux extensions. Séparation logique.

Vous pouvez considérer un délégué comme la classe parent d'une fonction, ou comme un espace réservé pour une méthode.

Jetons un coup d'œil au code. Supposons qu'il existe deux méthodes, une parlant anglais et une parlant chinois, et que les signatures de fonction de ces deux méthodes soient les mêmes.
public static void SayChinese(string name)
    {
      Console.WriteLine("你好," + name);
    }
    public static void SayEnglish(string name)
    {
      Console.WriteLine("hello," + name);
    }

Ensuite, lorsque nous appelons à l'extérieur,
  MyDelegate.SayChinese("张三");
  MyDelegate.SayEnglish("zhangsan");

Si nous voulons appeler ces deux méthodes différentes, devons-nous écrire des codes d'appel différents

Pouvons-nous appeler une seule méthode ? Modifiez le code comme suit :
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);
    }

De cette façon, une seule méthode, Say, est appelée.

Comment l'appeler ? Les trois méthodes d'appel suivantes :
      WithParaNoReturnEventHandler _WithParaNoReturnEventHandler = new WithParaNoReturnEventHandler(MyDelegate.SayChinese);
      MyDelegate.Say("张三",_WithParaNoReturnEventHandler);
      MyDelegate.Say("张三", delegate(string name) { Console.WriteLine("你好," + name); }); //匿名方法
      MyDelegate.Say("张三", (name) => { Console.WriteLine("你好," + name); }); //lambda表达式

Le code ci-dessus utilise plusieurs méthodes d'appel, et ces méthodes d'appel sont continuellement optimisées avec la mise à niveau de C#. La première est la méthode d'appel traditionnelle qui existait en C# 1.0, et la seconde est la méthode d'appel de méthode anonyme en C# 2.0. La méthode dite anonyme est une méthode sans nom. Il est plus approprié d'utiliser des méthodes anonymes lorsque la méthode. n'est appelé qu'une seule fois. Mais c'est tout. Expressions Lambda en C#3. En fait, les délégués génériques sont également pris en charge, et .NET 3.5 va encore plus loin et introduit un ensemble de types de délégués génériques appelés Func, qui peuvent obtenir plusieurs paramètres d'un type spécifié et renvoyer une autre valeur d'un type spécifié.

expression lambda

L'essence de l'expression lambda est une méthode, une méthode anonyme.

Si le corps de la méthode n'a qu'une seule ligne et aucune valeur de retour, vous pouvez également supprimer les accolades et les points-virgules.

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一样;

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

    Les événements
  • ne sont pas des instances déléguées - juste des méthodes d'ajout/suppression associées (similaires aux méthodes getter/assignment de la propriété).

Scénarios d'utilisation courants : transfert de valeur de formulaire, méthode de liaison au démarrage du thread, expression lambda, asynchrone, etc.

Exemple tiré de la vie réelle : tout le monde ne prend-il pas les billets de train maintenant ? Utiliser le cloud pour récupérer des billets équivaut à utiliser le mandat. Vous pouvez acheter les billets directement par vous-même, ou vous pouvez héberger les billets dans le cloud. pour récupérer les billets vous-même. , lorsque vous êtes sur le point de tirer, vous devez actualiser à tout moment, saisir le code de vérification lors de la commande, etc. Si vous utilisez la saisie de tickets cloud, il vous suffit de saisir. les informations de saisie du ticket à l'avance avant de libérer le ticket, et vous n'avez plus besoin de le faire. Vous êtes en charge, les tickets seront émis automatiquement et vous n'avez pas besoin de savoir comment Cloud Ticket Grabbing vous aide à récupérer les tickets. La même heure et le même numéro de train peuvent être transformés en une instance de délégation, et de nombreuses personnes utilisent cette instance de délégation pour récupérer des billets.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn