Verfasst von: bletra | 22. September 2010

Delegates (Teil 2 von 6): Generische Delegate

In .Net gibt es generische Listen, Methoden, Klassen, Schnittstellen und auch generische  Delegate.

public delegate void Del<T>(T item);
public static void Notify(int i) { }
Del<int> m1 = new Del<int>(Notify);

Zeile 1 definiert ein generisches Delegat. Erst bei der Instanzierung in Zeile 3 wird der Typ festgelegt.

Durch die Einführung von generischen Delegattypen im Namensraum System (ab .Net 2.0) werden eigene Delegatdefinitionen (weitestgehend) überflüssig:

public delegate TResult Func<in T, out TResult>(T arg)
public delegate void Action<in T>(T obj)

Func ist also der Delegattyp zur Aufnahme von Methoden mit Rückgabewert und Action für Methoden ohne Rückgabewert. Ab .Net 4.0 gibt es beide  Delegate mit bis zu 10 Argumenten. Damit sollte sich jeder Delegattyp definieren lassen (von .Net-Attributen abgesehen).

Es gibt auch vordefinierte generische Delegate, die bereits mit geeigneten Attributen versehen sind, wie z.B. AppDomainInitializer-Delegat. Oder für den häufigen Anwendungsbereich Sortieren mit Delegaten, gibt es Comparison<T>-Delegat.

Zur Veranschaulichung, betrachte ich ein Beispiel aus dem empfehlendswerten Buch Kompaktkurs C# 4.0, wie mit Hilfe des Func-Delegats auf der Konsole eine mathematische Funktion geplottet werden kann.

Anstelle der eigenen Definition

delegate double Function(double x);

Verwenden wir

Func<double, double>

Hier das vollständige Programm, das einmal einen Lambda-Ausdruck (Zeile 6) an die Funktion Plot übergibt und einmal eine statische Funktion (Zeile 8).

class Program
{
  static void Main(string[] args)
  {
    Console.WriteLine("Linear:");
    Plot(x => x);
    Console.WriteLine("\nParabel:");
    Plot(Parabel);
    Console.ReadLine();
  }
  static double Parabel(double x){return x*x;}
  static void Plot(Func<double, double> f)
  {
    //--- create a 50 x 50 drawing plane
    char[,] dot = new char[50, 50];
    for (int i = 0; i < dot.GetLength(0); i++)
      for (int j = 0; j < dot.GetLength(1); j++)
        dot[i, j] = ' ';
    //--- compute the function
    int height = dot.GetLength(0);
    for (int x = 0; x < dot.GetLength(1); x++)
    {
      int y = (int)f(x);
      if (0 <= y && y < height)
      {
        dot[(height - 1) - y, x] = '*';
      }
    }
    //--- draw the plot
    for (int i = 0; i < dot.GetLength(0); i++)
    {
      Console.Write('|');
      for (int j = 0; j < dot.GetLength(1); j++)
        Console.Write(dot[i, j]);
      Console.WriteLine();
    }
    for (int i = 0; i < dot.GetLength(1); i++)
      Console.Write('-');
  }
}

Wie zu erwarten, gilt auch für generische Delegate die Aussage bzgl. Kontravarianz und Kovarianz, wie im ersten Teil bereits dargestellt. Generische Delegate sind ja eigentlich nichts Besonderes,  schließlich werden bei der Deklaration der Delegatvariablen konkrete Datentypen angegeben. Die Kombination von Kovarianz und Kontravarianz veranschaulicht folgendes Codefragment, das ich von Microsoft übernommen habe.

public class Base {}
public class Derived : Base {}
public static Derived MyMethod(Base b)
{
  return b as Derived ?? new Derived();
}
// Covariant return type and contravariant parameter type.
Func<Derived, Base> f = MyMethod;
Base b = f(new Derived());</pre>

Wir wissen nun, was Delegate sind, wie wir unsere eigenen Delegattypen definieren können oder wie in diesem Artikel gezeigt, wie wir auf sehr allgemein definierte Delegattypen aus dem Namensraum System zurückgreifen können. Der nächste Teil wird sich mit Listen von Delegaten, den Multicastdelegaten befassen.

Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

Kategorien

%d Bloggern gefällt das: