Was verwenden Sie Delegaten in C #?
Was verwenden Sie Delegaten in C #?
Antworten:
Jetzt, da wir Lambda-Ausdrücke und anonyme Methoden in C # haben, verwende ich viel mehr Delegaten. In C # 1, wo Sie immer eine separate Methode haben mussten, um die Logik zu implementieren, war die Verwendung eines Delegaten oft nicht sinnvoll. In diesen Tagen benutze ich Delegierte für:
Delegierte sind für viele Zwecke sehr nützlich.
Ein solcher Zweck besteht darin, sie zum Filtern von Datensequenzen zu verwenden. In diesem Fall würden Sie einen Prädikatdelegaten verwenden, der ein Argument akzeptiert und je nach Implementierung des Delegaten selbst true oder false zurückgibt.
Hier ist ein dummes Beispiel - ich bin sicher, Sie können daraus etwas Nützlicheres extrapolieren:
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)
Methode ist der Delegat. Wobei ein Delegat als Parameter verwendet wird. Da Delegaten nur Funktionszeiger sind, wenn Sie den Methodennamen an den übergeben .Where(delegate)
, der zum Delegaten wird. Da inMyFamily einen booleschen Typ zurückgibt, wird er tatsächlich als Prädikat betrachtet. Prädikate sind nur Delegaten, die Boolesche Werte zurückgeben.
Eine weitere interessante Antwort gefunden:
Ein Mitarbeiter hat mir gerade diese Frage gestellt: Was ist der Sinn von Delegierten in .NET? Meine Antwort war sehr kurz und eine, die er online nicht gefunden hatte: die Ausführung einer Methode zu verzögern.
Quelle: LosTechies
Genau wie LINQ.
Sie können Delegaten verwenden, um funktionsbezogene Variablen und Parameter zu deklarieren.
Beispiel
Betrachten Sie das Muster "Ausleihen von Ressourcen". Sie möchten die Erstellung und Bereinigung einer Ressource steuern und gleichzeitig zulassen, dass Client-Code die Ressource dazwischen "ausleiht".
Dies deklariert einen Delegatentyp.
public delegate void DataReaderUser( System.Data.IDataReader dataReader );
Jede Methode, die dieser Signatur entspricht, kann verwendet werden, um einen Delegaten dieses Typs zu instanziieren. In C # 2.0 kann dies implizit einfach unter Verwendung des Methodennamens sowie unter Verwendung anonymer Methoden erfolgen.
Diese Methode verwendet den Typ als Parameter. Beachten Sie den Aufruf des Delegaten.
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;
}
}
}
Die Funktion kann mit einer anonymen Methode wie folgt aufgerufen werden. Beachten Sie, dass die anonyme Methode Variablen verwenden kann, die außerhalb von sich selbst deklariert sind . Dies ist äußerst praktisch (obwohl das Beispiel ein wenig erfunden ist).
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] );
} );
Delegaten können häufig anstelle einer Schnittstelle mit einer Methode verwendet werden. Ein häufiges Beispiel hierfür ist das Beobachtermuster. In anderen Sprachen können Sie Folgendes definieren, wenn Sie eine Benachrichtigung erhalten möchten, dass etwas passiert ist:
class IObserver{ void Notify(...); }
In C # wird dies häufiger durch Ereignisse ausgedrückt, bei denen der Handler ein Delegat ist, zum Beispiel:
myObject.SomeEvent += delegate{ Console.WriteLine("..."); };
Ein weiterer großartiger Ort, um Delegaten zu verwenden, wenn Sie ein Prädikat an eine Funktion übergeben müssen, z. B. wenn Sie eine Reihe von Elementen aus einer Liste auswählen:
myList.Where(i => i > 10);
Das Obige ist ein Beispiel für die Lambda-Syntax, die auch wie folgt geschrieben werden könnte:
myList.Where(delegate(int i){ return i > 10; });
Ein weiterer Ort, an dem es nützlich sein kann, Delegaten zu verwenden, ist die Registrierung von Factory-Funktionen, zum Beispiel:
myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
var widget = myFactory.BuildWidget(Widgets.Foo);
Ich hoffe das hilft!
Ich komme sehr spät dazu, aber ich hatte heute Probleme, den Zweck der Delegierten herauszufinden, und schrieb zwei einfache Programme, die die gleiche Ausgabe liefern, von der ich denke, dass sie ihren Zweck gut erklärt.
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);
}
}
Eine etwas andere Verwendung besteht darin, die Reflexion zu beschleunigen. Anstatt jedes Mal Reflektion zu verwenden, können Sie Delegate.CreateDelegate
einen (typisierten) Delegaten für eine Methode (a MethodInfo
) erstellen und stattdessen diesen Delegaten aufrufen. Dies ist dann pro Anruf viel schneller, da die Überprüfungen bereits durchgeführt wurden.
Mit Expression
können Sie das Gleiche auch tun, um Code im laufenden Betrieb zu erstellen. Sie können beispielsweise ganz einfach einen Expression
Operator erstellen , der den Operator + für einen zur Laufzeit ausgewählten Typ darstellt (um Operatorunterstützung für Generika bereitzustellen, die die Sprache nicht bietet). ;; und Sie können einen Expression
an einen typisierten Delegaten kompilierten Job erledigen.
Delegaten werden jedes Mal verwendet, wenn Sie Ereignisse verwenden - das ist der Mechanismus, mit dem sie arbeiten.
Darüber hinaus sind Delegaten sehr nützlich, wenn Sie beispielsweise LINQ-Abfragen verwenden. Beispielsweise benötigen viele LINQ-Abfragen (häufig Func<T,TResult>
) einen Delegaten , der zum Filtern verwendet werden kann.
Ein Beispiel könnte wie zu sehen ist hier . Sie haben eine Methode, um ein Objekt zu verarbeiten, das bestimmte Anforderungen erfüllt. Sie möchten das Objekt jedoch auf mehrere Arten verarbeiten können. Anstatt separate Methoden erstellen zu müssen, können Sie einfach eine übereinstimmende Methode zuweisen, die das Objekt einem Delegaten verarbeitet, und den Delegaten an die Methode übergeben, die die Objekte auswählt. Auf diese Weise können Sie der einen Auswahlmethode verschiedene Methoden zuweisen. Ich habe versucht, dies leicht verständlich zu machen.
Ich benutze Delegaten, um mit Threads zu kommunizieren.
Zum Beispiel könnte ich eine Win Forms App haben, die eine Datei herunterlädt. Die App startet einen Worker-Thread, um den Download durchzuführen (wodurch verhindert wird, dass die GUI blockiert). Der Worker-Thread verwendet Delegaten, um Statusmeldungen (z. B. Download-Fortschritt) an das Hauptprogramm zurückzusenden, damit die GUI die Statusleiste aktualisieren kann.
Für Event-Handler
Methode in Methodenparametern übergeben
Ereignisse, andere beliebige Operationen
Jedes Mal, wenn Sie das Verhalten kapseln möchten, es aber auf einheitliche Weise aufrufen möchten. Ereignishandler, Rückruffunktionen usw. Mit Interfaces und Casts können Sie ähnliche Aufgaben ausführen. Manchmal ist das Verhalten jedoch nicht unbedingt an einen Typ oder ein Objekt gebunden . Manchmal haben Sie nur ein Verhalten, das Sie einkapseln müssen.
Lazy Parameter Initialisierung! Neben allen vorherigen Antworten (Strategiemuster, Beobachtermuster usw.) können Sie mit Delegaten die verzögerte Initialisierung von Parametern durchführen. Angenommen, Sie haben eine Funktion Download (), die viel Zeit in Anspruch nimmt und ein bestimmtes DownloadedObject zurückgibt. Dieses Objekt wird abhängig von bestimmten Bedingungen von einem Speicher verwendet. Normalerweise würden Sie:
storage.Store(conditions, Download(item))
Mit Delegaten (genauer gesagt Lambdas) können Sie jedoch Folgendes tun, indem Sie die Signatur des Geschäfts so ändern, dass es eine Bedingung und eine Funktion <Item, DownloadedObject> erhält, und diese wie folgt verwenden:
storage.Store(conditions, (item) => Download(item))
Daher wertet der Speicher den Delegaten nur bei Bedarf aus und führt den Download abhängig von den Bedingungen aus.
Verwendung von Delegierten
Der Vergleichsparameter in In Array.Sort (Array T [], Vergleichsvergleich), List.Sort (Vergleichsvergleich) usw.
Soweit ich weiß, können Delegaten in Funktionszeiger konvertiert werden. Dies macht das Leben VIEL einfacher, wenn mit nativem Code zusammengearbeitet wird, der Funktionszeiger benötigt, da diese effektiv objektorientiert sein können, obwohl der ursprüngliche Programmierer dies nicht vorgesehen hat.
Delegaten werden verwendet, um eine Methode anhand ihrer Referenz aufzurufen. Beispielsweise:
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();
}
}