Quand utiliseriez-vous des délégués en C #? [fermé]


101

Quelle est votre utilisation des délégués en C #?


2
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."?
Niki

Réponses:


100

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;

class Program
{
    static void Main()
    {
        List<String> names = new List<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);
    }

    static Boolean inMyFamily(String name)
    {
        return name.EndsWith("Hare");
    }
}

11
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.

Source: LosTechies

Tout comme le fait LINQ.


+ 1 .. n'y avait pas pensé comme ça. Bon point
Luke101

12

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é.

public delegate void DataReaderUser( System.Data.IDataReader dataReader );

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é.

public class DataProvider
{
    protected string _connectionString;

    public DataProvider( string psConnectionString )
    {
        _connectionString = psConnectionString;
    }

    public void UseReader( string psSELECT, DataReaderUser readerUser )
    {
        using ( SqlConnection connection = new SqlConnection( _connectionString ) )
        try
        {
            SqlCommand command = new SqlCommand( psSELECT, connection );
            connection.Open();
            SqlDataReader reader = command.ExecuteReader();

            while ( reader.Read() )
                readerUser( reader );  // the delegate is invoked
        }
        catch ( System.Exception ex )
        {
            // handle exception
            throw 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] );
    } );

11

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:

class IObserver{ void Notify(...); }

En C #, cela est plus couramment exprimé à l'aide d'événements, où le gestionnaire est un délégué, par exemple:

myObject.SomeEvent += delegate{ Console.WriteLine("..."); };

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:

myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
var widget = myFactory.BuildWidget(Widgets.Foo);

J'espère que ça aide!


Bons exemples avec syntaxe .. Merci .. :)
Raghu

10

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;

public class Test {
    public const int MAX_VALUE = 255;
    public const int MIN_VALUE = 10;

    public static void 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");
        else
            Console.WriteLine("max and min value is not valid");
    }

    public static void checkMax(int a) {
        Console.Write("checkMax result of {0}: ", a);
        if (a < MAX_VALUE)
            Console.WriteLine("max value is valid");
        else
            Console.WriteLine("max value is not valid");
    }

    public static void checkMin(int a) {
        Console.Write("checkMin result of {0}: ", a);
        if (a > MIN_VALUE)
            Console.WriteLine("min value is valid");
        else
            Console.WriteLine("min value is not valid");
        Console.WriteLine("");
    }
}

public class Driver {
    public static void Main(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;

public delegate void Valid(int a);

public class Test {
    public const int MAX_VALUE = 255;
    public const int MIN_VALUE = 10;

    public static void 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");
        else
            Console.WriteLine("max and min value is not valid");
    }

    public static void checkMax(int a) {
        Console.Write("checkMax result of {0}: ", a);
        if (a < MAX_VALUE)
            Console.WriteLine("max value is valid");
        else
            Console.WriteLine("max value is not valid");
    }

    public static void checkMin(int a) {
        Console.Write("checkMin result of {0}: ", a);
        if (a > MIN_VALUE)
            Console.WriteLine("min value is valid");
        else
            Console.WriteLine("min value is not valid");
        Console.WriteLine("");
    }
}

public class Driver {
    public static void Main(string [] args) {
        Valid v1 = new Valid(Test.checkInt);
        v1 += new Valid(Test.checkMax);
        v1 += new Valid(Test.checkMin);
        v1(1);
        v1(10);
        v1(20);
        v1(30);
        v1(254);
        v1(255);
        v1(256);
    }
}

5

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é.


5

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.


4

abonnement de gestionnaires d'événements à des événements


2

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.


1

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.



0

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.


0

Evénements, autres opérations anynch


0

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.


0

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.
Marc Gravell


0

Le paramètre de comparaison dans In Array.Sort (tableau T [], comparaison de comparaison), List.Sort (comparaison de comparaison), etc.


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.


0

Les délégués sont utilisés pour appeler une méthode par sa référence. Par exemple:

  delegate void del_(int no1,int no2);
class Math
{
   public static void add(int x,int y)
   {
     Console.WriteLine(x+y);
   }
   public static void sub(int x,int y)
   {
     Console.WriteLine(x-y);
   }
}



    class Program
    {
        static void Main(string[] args)
        {
            del_ d1 = new del_(Math.add);
            d1(10, 20);
            del_ d2 = new del_(Math.sub);
            d2(20, 10);
            Console.ReadKey();
        }
    }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.