web-dev-qa-db-fra.com

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

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

100
Maxime Rouiller

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ù il fallait 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)
  • Fils de départ
  • Rappels (par exemple pour les API asynchrones)
  • LINQ et similaire (List.Find, etc.)
  • Partout 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)
98
Jon Skeet

Les délégués sont très utiles à de nombreuses fins.

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 stupide - je suis sûr que vous pouvez extrapoler quelque chose de plus utile à partir de cela:

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

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 LINQ le fait.

13
Maxime Rouiller

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 entre les deux.

Cela déclare un type 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] );
    } );
12
harpo

Les délégués peuvent souvent être utilisés à la place d'une interface avec une méthode, un exemple courant serait le modèle d'observateur. Dans d'autres langues, si vous souhaitez recevoir une notification que quelque chose s'est produit, vous pouvez définir quelque chose comme:

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

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

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

Un autre excellent 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 les fonctions d'usine, par exemple:

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

J'espère que ça aide!

10
jonnii

J'arrive très tard mais j'ai eu 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);
    }
}
10
will

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.

De plus, 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.

5
Reed Copsey

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é (typé) à une méthode (un MethodInfo), et appelez 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 Expression qui représente l'opérateur + pour un type choisi à l'exécution (pour fournir l'opérateur prise en charge des génériques, que le langage ne fournit pas); et vous pouvez compiler un Expression vers un délégué tapé - travail effectué.

5
Marc Gravell

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

4
Manu

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

2
rookie1024

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

1
Danny Frencham

Utilisation des délégués

  1. Gestion des événements
  2. Multi Casting
0
Rajeshwaran S P

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

0
GregUzelac

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();
        }
    }
0
mahesh
  1. Pour gestionnaire d'événements

  2. Pour passer une méthode dans les paramètres d'une méthode

0
Patrick Desjardins

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 de stratégie. Divers autres usages peuvent être rassemblés, bien que plus ésotériques que ces deux premiers je pense.

0
x0n

Événements, autres opérations anynch

0
Jeffe

Chaque fois que vous souhaitez encapsuler un comportement, mais l'invoquer 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 object. Parfois, vous avez juste un comportement que vous devez encapsuler.

0
Bob King

Pour 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
Puppy

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 devez:

storage.Store(conditions, Download(item))

Cependant, avec les délégués (plus précisément, lambdas), vous pouvez faire ce qui suit, en changeant la signature du magasin afin qu'il reçoive une condition et un Func <Item, DownloadedObject> et l'utiliser comme ceci:

storage.Store(conditions, (item) => Download(item))

Par conséquent, le stockage n'évaluera le délégué que si nécessaire, exécutant le téléchargement en fonction des conditions.

0
Santiago Palladino