Voulez-vous dire les délégués dans le système de type .NET ou la syntaxe de délégué C #? Voulez-vous dire "quand utilisez-vous la syntaxe de délégué au lieu de la syntaxe d'expression lambda" ou voulez-vous dire "quand utilisez-vous des délégués au lieu de classes / interfaces / méthodes virtuelles / etc."?
Maintenant que nous avons des expressions lambda et des méthodes anonymes en C #, j'utilise beaucoup plus les délégués. En C # 1, où vous deviez toujours avoir une méthode distincte pour implémenter la logique, l'utilisation d'un délégué n'avait souvent aucun sens. Ces jours-ci, j'utilise des délégués pour:
Gestionnaires d'événements (pour GUI et plus)
Threads de départ
Rappels (par exemple pour les API asynchrones)
LINQ et similaires (List.Find etc.)
Partout ailleurs où je veux appliquer efficacement du code «modèle» avec une logique spécialisée à l'intérieur (où le délégué fournit la spécialisation)
Vaut la peine de mentionner le "push" dans Push LINQ?
Marc Gravell
3
Je ne sais pas comment je l'expliquerais brièvement sans rendre les choses plus confuses :) (On peut dire qu'il est couvert par les gestionnaires d'événements, LINQ et le modèle de toute façon!
Jon Skeet
1
Votre première phrase n'a pas beaucoup de sens.
senfo
3
Je sais ce que vous essayez de dire, mais je trouverais ce qui suit plus facile à lire: "Maintenant que nous avons des expressions lambda et des méthodes anonymes en C #, j'utilise beaucoup plus les délégués." Je sais que je suis pinailleur, mais j'ai vraiment dû lire cette phrase plusieurs fois avant qu'elle n'ait un sens pour moi.
senfo
4
+1 pour avoir osé défier le vénérable Mr Skeet ;-)
indra
29
Les délégués sont très utiles à de nombreuses fins.
L'un de ces objectifs est de les utiliser pour filtrer des séquences de données. Dans ce cas, vous utiliseriez un délégué de prédicat qui accepte un argument et renvoie vrai ou faux selon l'implémentation du délégué lui-même.
Voici un exemple idiot - je suis sûr que vous pouvez extrapoler quelque chose de plus utile à partir de ceci:
using System;
using System.Linq;
using System.Collections.Generic;classProgram{staticvoidMain(){List<String> names =newList<String>{"Nicole Hare","Michael Hare","Joe Hare","Sammy Hare","George Washington",};// Here I am passing "inMyFamily" to the "Where" extension method// on my List<String>. The C# compiler automatically creates // a delegate instance for me.IEnumerable<String> myFamily = names.Where(inMyFamily);foreach(String name in myFamily)Console.WriteLine(name);}staticBoolean inMyFamily(String name){return name.EndsWith("Hare");}}
La static Boolean inMyFamily(String name)méthode est le délégué. Où prend un délégué comme paramètre. Étant donné que les délégués ne sont que des pointeurs de fonction lorsque vous passez le nom de la méthode dans le .Where(delegate)qui devient le délégué. Comme inMyFamily renvoie un type booléen, il est en fait considéré comme un prédicat. Les prédicats ne sont que des délégués qui renvoient des booléens.
Landon Poch
4
"Les prédicats ne sont que des délégués qui renvoient des booléens." +1
daehaai
@LandonPoch ce commentaire aurait été mieux placé dans la réponse. moi, étant un débutant, je ne pouvais pas savoir où c'était. Merci.
Eakan Gopalakrishnan
@Eakan, je ne répondais pas vraiment à la question principale (quand utiliseriez-vous des délégués) alors je l'ai laissé en commentaire à la place.
Landon Poch le
14
J'ai trouvé une autre réponse intéressante:
Un collègue vient de me poser cette question - quel est l'intérêt des délégués dans .NET? Ma réponse était très courte et qu'il n'avait pas trouvée en ligne: retarder l'exécution d'une méthode.
Vous pouvez utiliser des délégués pour déclarer des variables et des paramètres de type fonction.
Exemple
Considérez le modèle «d'emprunt de ressources». Vous souhaitez contrôler la création et le nettoyage d'une ressource, tout en autorisant le code client à «emprunter» la ressource intermédiaire.
Toute méthode correspondant à cette signature peut être utilisée pour instancier un délégué de ce type. En C # 2.0, cela peut être fait implicitement, simplement en utilisant le nom de la méthode, ainsi qu'en utilisant des méthodes anonymes.
Cette méthode utilise le type comme paramètre. Notez l'invocation du délégué.
publicclassDataProvider{protectedstring _connectionString;publicDataProvider(string psConnectionString ){
_connectionString = psConnectionString;}publicvoidUseReader(string psSELECT,DataReaderUser readerUser ){
using (SqlConnection connection =newSqlConnection( _connectionString ))try{SqlCommand command =newSqlCommand( psSELECT, connection );
connection.Open();SqlDataReader reader = command.ExecuteReader();while( reader.Read())
readerUser( reader );// the delegate is invoked}catch(System.Exception ex ){// handle exceptionthrow ex;}}}
La fonction peut être appelée avec une méthode anonyme comme suit. Notez que la méthode anonyme peut utiliser des variables déclarées en dehors d'elle-même. C'est extrêmement pratique (bien que l'exemple soit un peu artificiel).
string sTableName ="test";string sQuery ="SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='"+ sTableName +"'";DataProvider.UseReader( sQuery,delegate(System.Data.IDataReader reader ){Console.WriteLine( sTableName +"."+ reader[0]);});
Les délégués peuvent souvent être utilisés à la place d'une interface avec une méthode, un exemple courant de ceci serait le modèle d'observateur. Dans d'autres langues, si vous souhaitez recevoir une notification indiquant que quelque chose s'est produit, vous pouvez définir quelque chose comme:
classIObserver{voidNotify(...);}
En C #, cela est plus couramment exprimé à l'aide d'événements, où le gestionnaire est un délégué, par exemple:
Un autre bon endroit pour utiliser des délégués si vous devez passer un prédicat dans une fonction, par exemple lors de la sélection d'un ensemble d'éléments dans une liste:
myList.Where(i => i >10);
Ce qui précède est un exemple de la syntaxe lambda, qui aurait également pu être écrite comme suit:
myList.Where(delegate(int i){return i >10;});
Un autre endroit où il peut être utile d'utiliser des délégués est d'enregistrer des fonctions d'usine, par exemple:
J'arrive très tard mais j'avais du mal à comprendre le but des délégués aujourd'hui et j'ai écrit deux programmes simples qui donnent le même résultat qui, je pense, explique bien leur but.
NoDelegates.cs
using System;publicclassTest{publicconstint MAX_VALUE =255;publicconstint MIN_VALUE =10;publicstaticvoid checkInt(int a){Console.Write("checkInt result of {0}: ", a);if(a < MAX_VALUE && a > MIN_VALUE)Console.WriteLine("max and min value is valid");elseConsole.WriteLine("max and min value is not valid");}publicstaticvoid checkMax(int a){Console.Write("checkMax result of {0}: ", a);if(a < MAX_VALUE)Console.WriteLine("max value is valid");elseConsole.WriteLine("max value is not valid");}publicstaticvoid checkMin(int a){Console.Write("checkMin result of {0}: ", a);if(a > MIN_VALUE)Console.WriteLine("min value is valid");elseConsole.WriteLine("min value is not valid");Console.WriteLine("");}}publicclassDriver{publicstaticvoidMain(string[] args){Test.checkInt(1);Test.checkMax(1);Test.checkMin(1);Test.checkInt(10);Test.checkMax(10);Test.checkMin(10);Test.checkInt(20);Test.checkMax(20);Test.checkMin(20);Test.checkInt(30);Test.checkMax(30);Test.checkMin(30);Test.checkInt(254);Test.checkMax(254);Test.checkMin(254);Test.checkInt(255);Test.checkMax(255);Test.checkMin(255);Test.checkInt(256);Test.checkMax(256);Test.checkMin(256);}}
Delegates.cs
using System;publicdelegatevoidValid(int a);publicclassTest{publicconstint MAX_VALUE =255;publicconstint MIN_VALUE =10;publicstaticvoid checkInt(int a){Console.Write("checkInt result of {0}: ", a);if(a < MAX_VALUE && a > MIN_VALUE)Console.WriteLine("max and min value is valid");elseConsole.WriteLine("max and min value is not valid");}publicstaticvoid checkMax(int a){Console.Write("checkMax result of {0}: ", a);if(a < MAX_VALUE)Console.WriteLine("max value is valid");elseConsole.WriteLine("max value is not valid");}publicstaticvoid checkMin(int a){Console.Write("checkMin result of {0}: ", a);if(a > MIN_VALUE)Console.WriteLine("min value is valid");elseConsole.WriteLine("min value is not valid");Console.WriteLine("");}}publicclassDriver{publicstaticvoidMain(string[] args){Valid v1 =newValid(Test.checkInt);
v1 +=newValid(Test.checkMax);
v1 +=newValid(Test.checkMin);
v1(1);
v1(10);
v1(20);
v1(30);
v1(254);
v1(255);
v1(256);}}
Une utilisation légèrement différente consiste à accélérer la réflexion; c'est-à-dire qu'au lieu d'utiliser la réflexion à chaque fois, vous pouvez utiliser Delegate.CreateDelegatepour créer un délégué (tapé) à une méthode (a MethodInfo), et appeler ce délégué à la place. C'est alors beaucoup plus rapide par appel, car les vérifications ont déjà été effectuées.
Avec Expression, vous pouvez également faire de même pour créer du code à la volée - par exemple, vous pouvez facilement créer un Expressionqui représente l'opérateur + pour un type choisi au moment de l'exécution (pour fournir un support d'opérateur pour les génériques, que le langage ne fournit pas) ; et vous pouvez compiler un Expressionvers un délégué tapé - travail terminé.
Les délégués sont utilisés chaque fois que vous utilisez des événements - c'est le mécanisme par lequel ils fonctionnent.
En outre, les délégués sont très utiles pour des choses telles que l'utilisation de requêtes LINQ. Par exemple, de nombreuses requêtes LINQ prennent un délégué (souvent Func<T,TResult>) qui peut être utilisé pour le filtrage.
Un exemple pourrait être comme vu ici . Vous disposez d'une méthode pour traiter un objet qui répond à certaines exigences. Cependant, vous souhaitez pouvoir traiter l'objet de plusieurs manières. Au lieu d'avoir à créer des méthodes distinctes, vous pouvez simplement attribuer une méthode correspondante qui traite l'objet à un délégué et transmettre le délégué à la méthode qui sélectionne les objets. De cette façon, vous pouvez affecter différentes méthodes à la méthode de sélection unique. J'ai essayé de rendre cela facilement compréhensible.
J'utilise des délégués pour communiquer avec les threads.
Par exemple, je pourrais avoir une application Win Forms qui télécharge un fichier. L'application démarre un thread de travail pour effectuer le téléchargement (ce qui empêche l'interface graphique de se verrouiller). Le thread de travail utilise des délégués pour envoyer des messages d'état (par exemple, la progression du téléchargement) au programme principal, afin que l'interface graphique puisse mettre à jour la barre d'état.
La première ligne d'utilisation consiste à remplacer le modèle Observateur / Observable (événements). Le second, une belle version élégante du modèle Strategy. Divers autres usages peuvent être rassemblés, bien que plus ésotériques que ces deux premiers je pense.
Chaque fois que vous souhaitez encapsuler un comportement, mais invoquez-le de manière uniforme. Gestionnaires d'événements, fonctions de rappel, etc. Vous pouvez accomplir des choses similaires en utilisant des interfaces et des transtypages, mais parfois, le comportement n'est pas nécessairement lié à un type ou à un objet . Parfois, vous n'avez qu'un comportement que vous devez encapsuler.
Initialisation des paramètres paresseux! Outre toutes les réponses précédentes (modèle de stratégie, modèle d'observateur, etc.), les délégués vous permettent de gérer l'initialisation paresseuse des paramètres. Par exemple, supposons que vous ayez une fonction Download () qui prend beaucoup de temps et renvoie un certain DownloadedObject. Cet objet est consommé par un Stockage en fonction de certaines Conditions. En règle générale, vous:
storage.Store(conditions,Download(item))
Cependant, avec les délégués (plus précisément, les lambdas), vous pouvez faire ce qui suit, en changeant la signature de store afin qu'il reçoive une condition et un Func <Item, DownloadedObject> et l'utilise comme ceci:
storage.Store(conditions,(item)=>Download(item))
Par conséquent, le stockage n'évaluera le délégué que si nécessaire, en exécutant le téléchargement en fonction des conditions.
Point mineur, mais concernant "plus précisément, lambdas" - vous pourriez faire de même avec une méthode anonyme en C # 2.0, même si ce serait plus détaillé: delegate (ItemType item) {[return] Download (item);}
Marc Gravell
Bien sûr, comme LINQ: les lambdas ne sont rien de plus que du sucre syntaxique pour les délégués. Ils ont simplement rendu les délégués plus accessibles.
Santiago Palladino
Les lambdas sont un peu plus que de simples délégués, car ils sont convertibles en arborescences d'expression ainsi qu'en délégués.
Jon Skeet
Eh bien, les lambdas peuvent également être compilées en expressions, qui sont complètement différentes des délégués. Mais votre exemple a utilisé Func <,>, qui peut être utilisé à partir d'une méthode anon. Les expressions seraient extrêmement pénibles à écrire en C # 2.0.
Autant que je sache, les délégués peuvent être convertis en pointeurs de fonction. Cela rend la vie BEAUCOUP plus facile lors de l'interopérabilité avec du code natif qui prend des pointeurs de fonction, car ils peuvent effectivement être orientés objet, même si le programmeur d'origine n'a pris aucune disposition pour que cela se produise.
Réponses:
Maintenant que nous avons des expressions lambda et des méthodes anonymes en C #, j'utilise beaucoup plus les délégués. En C # 1, où vous deviez toujours avoir une méthode distincte pour implémenter la logique, l'utilisation d'un délégué n'avait souvent aucun sens. Ces jours-ci, j'utilise des délégués pour:
la source
Les délégués sont très utiles à de nombreuses fins.
L'un de ces objectifs est de les utiliser pour filtrer des séquences de données. Dans ce cas, vous utiliseriez un délégué de prédicat qui accepte un argument et renvoie vrai ou faux selon l'implémentation du délégué lui-même.
Voici un exemple idiot - je suis sûr que vous pouvez extrapoler quelque chose de plus utile à partir de ceci:
la source
static Boolean inMyFamily(String name)
méthode est le délégué. Où prend un délégué comme paramètre. Étant donné que les délégués ne sont que des pointeurs de fonction lorsque vous passez le nom de la méthode dans le.Where(delegate)
qui devient le délégué. Comme inMyFamily renvoie un type booléen, il est en fait considéré comme un prédicat. Les prédicats ne sont que des délégués qui renvoient des booléens.J'ai trouvé une autre réponse intéressante:
Source: LosTechies
Tout comme le fait LINQ.
la source
Vous pouvez utiliser des délégués pour déclarer des variables et des paramètres de type fonction.
Exemple
Considérez le modèle «d'emprunt de ressources». Vous souhaitez contrôler la création et le nettoyage d'une ressource, tout en autorisant le code client à «emprunter» la ressource intermédiaire.
Cela déclare un type de délégué.
Toute méthode correspondant à cette signature peut être utilisée pour instancier un délégué de ce type. En C # 2.0, cela peut être fait implicitement, simplement en utilisant le nom de la méthode, ainsi qu'en utilisant des méthodes anonymes.
Cette méthode utilise le type comme paramètre. Notez l'invocation du délégué.
La fonction peut être appelée avec une méthode anonyme comme suit. Notez que la méthode anonyme peut utiliser des variables déclarées en dehors d'elle-même. C'est extrêmement pratique (bien que l'exemple soit un peu artificiel).
la source
Les délégués peuvent souvent être utilisés à la place d'une interface avec une méthode, un exemple courant de ceci serait le modèle d'observateur. Dans d'autres langues, si vous souhaitez recevoir une notification indiquant que quelque chose s'est produit, vous pouvez définir quelque chose comme:
En C #, cela est plus couramment exprimé à l'aide d'événements, où le gestionnaire est un délégué, par exemple:
Un autre bon endroit pour utiliser des délégués si vous devez passer un prédicat dans une fonction, par exemple lors de la sélection d'un ensemble d'éléments dans une liste:
Ce qui précède est un exemple de la syntaxe lambda, qui aurait également pu être écrite comme suit:
Un autre endroit où il peut être utile d'utiliser des délégués est d'enregistrer des fonctions d'usine, par exemple:
J'espère que ça aide!
la source
J'arrive très tard mais j'avais du mal à comprendre le but des délégués aujourd'hui et j'ai écrit deux programmes simples qui donnent le même résultat qui, je pense, explique bien leur but.
NoDelegates.cs
Delegates.cs
la source
Une utilisation légèrement différente consiste à accélérer la réflexion; c'est-à-dire qu'au lieu d'utiliser la réflexion à chaque fois, vous pouvez utiliser
Delegate.CreateDelegate
pour créer un délégué (tapé) à une méthode (aMethodInfo
), et appeler ce délégué à la place. C'est alors beaucoup plus rapide par appel, car les vérifications ont déjà été effectuées.Avec
Expression
, vous pouvez également faire de même pour créer du code à la volée - par exemple, vous pouvez facilement créer unExpression
qui représente l'opérateur + pour un type choisi au moment de l'exécution (pour fournir un support d'opérateur pour les génériques, que le langage ne fournit pas) ; et vous pouvez compiler unExpression
vers un délégué tapé - travail terminé.la source
Les délégués sont utilisés chaque fois que vous utilisez des événements - c'est le mécanisme par lequel ils fonctionnent.
En outre, les délégués sont très utiles pour des choses telles que l'utilisation de requêtes LINQ. Par exemple, de nombreuses requêtes LINQ prennent un délégué (souvent
Func<T,TResult>
) qui peut être utilisé pour le filtrage.la source
abonnement de gestionnaires d'événements à des événements
la source
Un exemple pourrait être comme vu ici . Vous disposez d'une méthode pour traiter un objet qui répond à certaines exigences. Cependant, vous souhaitez pouvoir traiter l'objet de plusieurs manières. Au lieu d'avoir à créer des méthodes distinctes, vous pouvez simplement attribuer une méthode correspondante qui traite l'objet à un délégué et transmettre le délégué à la méthode qui sélectionne les objets. De cette façon, vous pouvez affecter différentes méthodes à la méthode de sélection unique. J'ai essayé de rendre cela facilement compréhensible.
la source
J'utilise des délégués pour communiquer avec les threads.
Par exemple, je pourrais avoir une application Win Forms qui télécharge un fichier. L'application démarre un thread de travail pour effectuer le téléchargement (ce qui empêche l'interface graphique de se verrouiller). Le thread de travail utilise des délégués pour envoyer des messages d'état (par exemple, la progression du téléchargement) au programme principal, afin que l'interface graphique puisse mettre à jour la barre d'état.
la source
Pour le gestionnaire d'événements
Pour passer une méthode dans des paramètres de méthode
la source
La première ligne d'utilisation consiste à remplacer le modèle Observateur / Observable (événements). Le second, une belle version élégante du modèle Strategy. Divers autres usages peuvent être rassemblés, bien que plus ésotériques que ces deux premiers je pense.
la source
Evénements, autres opérations anynch
la source
Chaque fois que vous souhaitez encapsuler un comportement, mais invoquez-le de manière uniforme. Gestionnaires d'événements, fonctions de rappel, etc. Vous pouvez accomplir des choses similaires en utilisant des interfaces et des transtypages, mais parfois, le comportement n'est pas nécessairement lié à un type ou à un objet . Parfois, vous n'avez qu'un comportement que vous devez encapsuler.
la source
Initialisation des paramètres paresseux! Outre toutes les réponses précédentes (modèle de stratégie, modèle d'observateur, etc.), les délégués vous permettent de gérer l'initialisation paresseuse des paramètres. Par exemple, supposons que vous ayez une fonction Download () qui prend beaucoup de temps et renvoie un certain DownloadedObject. Cet objet est consommé par un Stockage en fonction de certaines Conditions. En règle générale, vous:
Cependant, avec les délégués (plus précisément, les lambdas), vous pouvez faire ce qui suit, en changeant la signature de store afin qu'il reçoive une condition et un Func <Item, DownloadedObject> et l'utilise comme ceci:
Par conséquent, le stockage n'évaluera le délégué que si nécessaire, en exécutant le téléchargement en fonction des conditions.
la source
Utilisation des délégués
la source
Le paramètre de comparaison dans In Array.Sort (tableau T [], comparaison de comparaison), List.Sort (comparaison de comparaison), etc.
la source
Autant que je sache, les délégués peuvent être convertis en pointeurs de fonction. Cela rend la vie BEAUCOUP plus facile lors de l'interopérabilité avec du code natif qui prend des pointeurs de fonction, car ils peuvent effectivement être orientés objet, même si le programmeur d'origine n'a pris aucune disposition pour que cela se produise.
la source
Les délégués sont utilisés pour appeler une méthode par sa référence. Par exemple:
la source