Donnerstag, 3. Februar 2011

C#: Delegaten (Funktionspointer)

Delegaten sind ganz einfache Funktionspointer in C#.
Ein Pointer ist ein Zeiger oder anders gesagt, ein "Link" auf eine Variable oder eine Funktion. In C# besteht sozusagen alles aus Pointern, doch in C/C++ besteht da ein gewisser Unterschied. Wer sich näher mit Pointern befassen will, liest bitte das da:
http://www.mathematik.uni-marburg.de/~cpp/pointer/index.html

Ein Funktionspointer ist also ein Zeiger auf eine Funktion. Mit Funktionspointern/Delegates können nur statische Funktionen angesprochen werden. (really? c++: jein (es gibt einen KOMPLIZIERTEN Trick, aber normalerweise kann man in c++ nur auf statische Funktionen zugreifen.)
(Erklärung static)

Man kann mit einem kleinen Trick auch private/protected-Funktionen ANDERER Klassen ansprechen, wenn man den Delegaten in der jeweiligen Klasse initialisiert.

Ein Funktionspointer sieht normalerweise so aus (C/C++/C#):

void (*myFuncPtr)(void);

Das ist ein Funktionspointer ohne Parameter und Rückgabetyp. Das sieht kompliziert aus und das ist es auch. Ein Delegat ist viel einfacher zu implementieren:

delegate void MyFuncPtr(void);

Man schreibt also den Delegaten aus wie einen normalen Prototypen einer Funktion - einfach mit dem Wörtchen delegate davor. Benutzen kann man ihn jetzt wie eine normale Variable/Funktion, für den Funktionstyp ohne Parameter und Rückgabetyp:

delegate void VoidFuncPtr(void);
...
VoidFuncPtr a=null;
...
static void voidFunction(void) {...}
...
a=voidFunction;
...
a(); <-- führt jetzt voidFunction() aus.


Mit Parametern und Rückgabetypen ist es genau so einfach, einfach statt dem Wörtchen void was anderes hinschreiben:

delegate int IntFuncPtr(int a);
...
IntFuncPtr b=null;
...
static int intFunction(int a) {... return a;}
...
b=intFunction;
...
int c=b(123) <-- Führt jetzt intFunction aus mit den Parameter 123;


Mit Delegaten kann man auf verborgene Member (private und protected) in ANDEREN Klassen zugreifen, mit diesem kleinen Trick:

delegate void VoidFuncPtr(void);
...
class A
{
  VoidFuncPtr func;
}

class B
{
  private static void PrivateFunction(void) {...}
  public static void ExposeFunction(A target)
  {
    target.VoidFuncPtr = PrivateFunction;
  }
}
...
A myTargetClassA=new A();
B mySourceClassB=new B();
...
mySourceClassB.ExposeFunction(myTargetClassA);
...
myTargetClassA.func();

Dieses kleine Konstrukt führt PrivateFunction (in B) aus, auch wenn der Aufruf zB. in Klasse C steht und von A aus aufgerufen wird - obwohl PrivateFunction eigentlich nur von B ausgeführt werden dürfte. Ich finde, das ist eine sehr nützliche Entwicklung.

Keine Kommentare:

Kommentar veröffentlichen