Quelle est votre utilisation des délégués en C #?
Quelle est votre utilisation des délégués en C #?
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:
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");
}
}
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:
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.
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] );
} );
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!
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);
}
}
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 (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 Expression
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 un Expression
vers 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.
Pour le gestionnaire d'événements
Pour passer une méthode dans des paramètres de méthode
Evénements, autres opérations anynch
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.
Utilisation des délégués
Le paramètre de comparaison dans In Array.Sort (tableau T [], comparaison de comparaison), List.Sort (comparaison de comparaison), etc.
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.
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();
}
}