Gewusst wie: Definieren und Verwenden von Delegaten (C++/CLI)

In diesem Artikel wird erläutert, wie Stellvertretungen in C++/CLI definiert und verwendet werden.

Obwohl .NET Framework eine Reihe von Delegaten bereitstellt, müssen Sie möglicherweise neue Stellvertretungen definieren.

Im folgenden Codebeispiel wird eine Stellvertretung definiert, die den Namen hat MyCallback. Der Ereignisbehandlungscode – die Funktion, die aufgerufen wird, wenn dieser neue Delegat ausgelöst wird – muss über einen Rückgabetyp void verfügen und einen String Verweis annehmen.

Die Standard-Funktion verwendet eine statische Methode, die durch SomeClass die Instanziierung des MyCallback Delegaten definiert wird. Der Delegat wird dann zu einer alternativen Methode zum Aufrufen dieser Funktion, wie das Senden der Zeichenfolge "single" an das Delegate-Objekt veranschaulicht. Als Nächstes werden zusätzliche Instanzen miteinander MyCallback verknüpft und dann durch einen Aufruf des Delegatenobjekts ausgeführt.

// use_delegate.cpp
// compile with: /clr
using namespace System;

ref class SomeClass
{
public:
   static void Func(String^ str)
   {
      Console::WriteLine("static SomeClass::Func - {0}", str);
   }
};

ref class OtherClass
{
public:
   OtherClass( Int32 n )
   {
      num = n;
   }

   void Method(String^ str)
   {
      Console::WriteLine("OtherClass::Method - {0}, num = {1}",
         str, num);
   }

   Int32 num;
};

delegate void MyCallback(String^ str);

int main( )
{
   MyCallback^ callback = gcnew MyCallback(SomeClass::Func);
   callback("single");

   callback += gcnew MyCallback(SomeClass::Func);

   OtherClass^ f = gcnew OtherClass(99);
   callback += gcnew MyCallback(f, &OtherClass::Method);

   f = gcnew OtherClass(100);
   callback += gcnew MyCallback(f, &OtherClass::Method);

   callback("chained");

   return 0;
}
static SomeClass::Func - single
static SomeClass::Func - chained
static SomeClass::Func - chained
OtherClass::Method - chained, num = 99
OtherClass::Method - chained, num = 100

Das nächste Codebeispiel zeigt, wie ein Delegat einem Mitglied einer Wertklasse zugeordnet wird.

// mcppv2_del_mem_value_class.cpp
// compile with: /clr
using namespace System;
public delegate void MyDel();

value class A {
public:
   void func1() {
      Console::WriteLine("test");
   }
};

int main() {
   A a;
   A^ ah = a;
   MyDel^ f = gcnew MyDel(a, &A::func1);   // implicit box of a
   f();
   MyDel^ f2 = gcnew MyDel(ah, &A::func1);
   f2();
}
test
test

So verfassen Sie Stellvertretungen

Sie können den Operator "-" verwenden, um einen Komponentendelegat aus einem zusammengesetzten Delegaten zu entfernen.

// mcppv2_compose_delegates.cpp
// compile with: /clr
using namespace System;

delegate void MyDelegate(String ^ s);

ref class MyClass {
public:
   static void Hello(String ^ s) {
      Console::WriteLine("Hello, {0}!", s);
   }

   static void Goodbye(String ^ s) {
      Console::WriteLine("  Goodbye, {0}!", s);
   }
};

int main() {

   MyDelegate ^ a = gcnew MyDelegate(MyClass::Hello);
   MyDelegate ^ b = gcnew MyDelegate(MyClass::Goodbye);
   MyDelegate ^ c = a + b;
   MyDelegate ^ d = c - a;

   Console::WriteLine("Invoking delegate a:");
   a("A");
   Console::WriteLine("Invoking delegate b:");
   b("B");
   Console::WriteLine("Invoking delegate c:");
   c("C");
   Console::WriteLine("Invoking delegate d:");
   d("D");
}

Ausgabe

Invoking delegate a:
Hello, A!
Invoking delegate b:
  Goodbye, B!
Invoking delegate c:
Hello, C!
  Goodbye, C!
Invoking delegate d:
  Goodbye, D!

Übergeben eines Delegaten^ an eine systemeigene Funktion, die einen Funktionszeiger erwartet

Aus einer verwalteten Komponente können Sie eine systemeigene Funktion mit Funktionszeigerparametern aufrufen, in denen die systemeigene Funktion dann die Memberfunktion des Delegaten der verwalteten Komponente aufrufen kann.

In diesem Beispiel wird die DLL erstellt, die die systemeigene Funktion exportiert:

// delegate_to_native_function.cpp
// compile with: /LD
#include < windows.h >
extern "C" {
   __declspec(dllexport)
   void nativeFunction(void (CALLBACK *mgdFunc)(const char* str)) {
      mgdFunc("Call to Managed Function");
   }
}

Im nächsten Beispiel wird die DLL verwendet und ein Delegatenhandle an die systemeigene Funktion übergeben, die einen Funktionszeiger erwartet.

// delegate_to_native_function_2.cpp
// compile with: /clr
using namespace System;
using namespace System::Runtime::InteropServices;

delegate void Del(String ^s);
public ref class A {
public:
   void delMember(String ^s) {
      Console::WriteLine(s);
   }
};

[DllImportAttribute("delegate_to_native_function", CharSet=CharSet::Ansi)]
extern "C" void nativeFunction(Del ^d);

int main() {
   A ^a = gcnew A;
   Del ^d = gcnew Del(a, &A::delMember);
   nativeFunction(d);   // Call to native function
}

Ausgabe

Call to Managed Function

So ordnen Sie Stellvertretungen nicht verwalteten Funktionen zu

Um einer Stellvertretung eine systemeigene Funktion zuzuordnen, müssen Sie die systemeigene Funktion in einem verwalteten Typ umschließen und die Funktion deklarieren, die über PInvokediese aufgerufen werden soll.

// mcppv2_del_to_umnangd_func.cpp
// compile with: /clr
#pragma unmanaged
extern "C" void printf(const char*, ...);
class A {
public:
   static void func(char* s) {
      printf(s);
   }
};

#pragma managed
public delegate void func(char*);

ref class B {
   A* ap;

public:
   B(A* ap):ap(ap) {}
   void func(char* s) {
      ap->func(s);
   }
};

int main() {
   A* a = new A;
   B^ b = gcnew B(a);
   func^ f = gcnew func(b, &B::func);
   f("hello");
   delete a;
}

Ausgabe

hello

So verwenden Sie ungebundene Stellvertretungen

Sie können eine ungebundene Stellvertretung verwenden, um eine Instanz des Typs zu übergeben, deren Funktion aufgerufen werden soll, wenn die Stellvertretung aufgerufen wird.

Ungebundene Stellvertretungen sind besonders nützlich, wenn Sie die Objekte in einer Auflistung durchlaufen möchten , indem Sie sie für jede Instanz in Schlüsselwort (keyword)s verwenden und eine Memberfunktion für jede Instanz aufrufen.

Hier erfahren Sie, wie Sie gebundene und ungebundene Stellvertretungen deklarieren, instanziieren und aufrufen:

Aktion Gebundene Stellvertretungen Nicht gebundene Delegate
Declare Die Stellvertretungssignatur muss mit der Signatur der Funktion übereinstimmen, die Sie über die Stellvertretung aufrufen möchten. Der erste Parameter der Delegatensignatur ist der Typ des this Objekts, das Sie aufrufen möchten.

Nach dem ersten Parameter muss die Stellvertretungssignatur mit der Signatur der Funktion übereinstimmen, die Sie über den Delegaten aufrufen möchten.
Instanziieren Wenn Sie einen gebundenen Delegaten instanziieren, können Sie eine Instanzfunktion oder eine globale oder statische Memberfunktion angeben.

Zum Angeben einer Instanzfunktion ist der erste Parameter eine Instanz des Typs, dessen Memberfunktion Sie aufrufen möchten, und der zweite Parameter die Adresse der Funktion, die Sie aufrufen möchten.

Wenn Sie eine globale oder statische Memberfunktion aufrufen möchten, übergeben Sie einfach den Namen einer globalen Funktion oder den Namen der statischen Memberfunktion.
Wenn Sie eine ungebundene Stellvertretung instanziieren, übergeben Sie einfach die Adresse der Funktion, die Sie aufrufen möchten.
Call Wenn Sie einen gebundenen Delegaten aufrufen, übergeben Sie einfach die Parameter, die von der Stellvertretungssignatur benötigt werden. Identisch mit einer gebundenen Stellvertretung, aber denken Sie daran, dass der erste Parameter eine Instanz des Objekts sein muss, das die Funktion enthält, die Sie aufrufen möchten.

In diesem Beispiel wird veranschaulicht, wie ungebundene Stellvertretungen deklariert, instanziiert und angerufen werden:

// unbound_delegates.cpp
// compile with: /clr
ref struct A {
   A(){}
   A(int i) : m_i(i) {}
   void Print(int i) { System::Console::WriteLine(m_i + i);}

private:
   int m_i;
};

value struct V {
   void Print() { System::Console::WriteLine(m_i);}
   int m_i;
};

delegate void Delegate1(A^, int i);
delegate void Delegate2(A%, int i);

delegate void Delegate3(interior_ptr<V>);
delegate void Delegate4(V%);

delegate void Delegate5(int i);
delegate void Delegate6();

int main() {
   A^ a1 = gcnew A(1);
   A% a2 = *gcnew A(2);

   Delegate1 ^ Unbound_Delegate1 = gcnew Delegate1(&A::Print);
   // delegate takes a handle
   Unbound_Delegate1(a1, 1);
   Unbound_Delegate1(%a2, 1);

   Delegate2 ^ Unbound_Delegate2 = gcnew Delegate2(&A::Print);
   // delegate takes a tracking reference (must deference the handle)
   Unbound_Delegate2(*a1, 1);
   Unbound_Delegate2(a2, 1);

   // instantiate a bound delegate to an instance member function
   Delegate5 ^ Bound_Del = gcnew Delegate5(a1, &A::Print);
   Bound_Del(1);

   // instantiate value types
   V v1 = {7};
   V v2 = {8};

   Delegate3 ^ Unbound_Delegate3 = gcnew Delegate3(&V::Print);
   Unbound_Delegate3(&v1);
   Unbound_Delegate3(&v2);

   Delegate4 ^ Unbound_Delegate4 = gcnew Delegate4(&V::Print);
   Unbound_Delegate4(v1);
   Unbound_Delegate4(v2);

   Delegate6 ^ Bound_Delegate3 = gcnew Delegate6(v1, &V::Print);
   Bound_Delegate3();
}

Ausgabe

2
3
2
3
2
7
8
7
8
7

Im nächsten Beispiel wird gezeigt, wie ungebundene Stellvertretungen und die einzelnen Elemente in Schlüsselwort (keyword) verwendet werden, um Objekte in einer Auflistung zu durchlaufen und eine Memberfunktion für jede Instanz aufzurufen.

// unbound_delegates_2.cpp
// compile with: /clr
using namespace System;

ref class RefClass {
   String^ _Str;

public:
   RefClass( String^ str ) : _Str( str ) {}
   void Print() { Console::Write( _Str ); }
};

delegate void PrintDelegate( RefClass^ );

int main() {
   PrintDelegate^ d = gcnew PrintDelegate( &RefClass::Print );

   array< RefClass^ >^ a = gcnew array<RefClass^>( 10 );

   for ( int i = 0; i < a->Length; ++i )
      a[i] = gcnew RefClass( i.ToString() );

   for each ( RefClass^ R in a )
      d( R );

   Console::WriteLine();
}

In diesem Beispiel wird eine ungebundene Stellvertretung für die Accessorfunktionen einer Eigenschaft erstellt:

// unbound_delegates_3.cpp
// compile with: /clr
ref struct B {
   property int P1 {
      int get() { return m_i; }
      void set(int i) { m_i = i; }
   }

private:
   int m_i;
};

delegate void DelBSet(B^, int);
delegate int DelBGet(B^);

int main() {
   B^ b = gcnew B;

   DelBSet^ delBSet = gcnew DelBSet(&B::P1::set);
   delBSet(b, 11);

   DelBGet^ delBGet = gcnew DelBGet(&B::P1::get);
   System::Console::WriteLine(delBGet(b));
}

Ausgabe

11

Das folgende Beispiel zeigt, wie Sie einen Multicastdelegat aufrufen, wobei eine Instanz gebunden ist und eine Instanz ungebunden ist.

// unbound_delegates_4.cpp
// compile with: /clr
ref class R {
public:
   R(int i) : m_i(i) {}

   void f(R ^ r) {
      System::Console::WriteLine("in f(R ^ r)");
   }

   void f() {
      System::Console::WriteLine("in f()");
   }

private:
   int m_i;
};

delegate void Del(R ^);

int main() {
   R ^r1 = gcnew R(11);
   R ^r2 = gcnew R(12);

   Del^ d = gcnew Del(r1, &R::f);
   d += gcnew Del(&R::f);
   d(r2);
};

Ausgabe

in f(R ^ r)
in f()

Im nächsten Beispiel wird gezeigt, wie Sie einen ungebundenen generischen Delegat erstellen und aufrufen.

// unbound_delegates_5.cpp
// compile with: /clr
ref struct R {
   R(int i) : m_i(i) {}

   int f(R ^) { return 999; }
   int f() { return m_i + 5; }

   int m_i;
};

value struct V {
   int f(V%) { return 999; }
   int f() { return m_i + 5; }

   int m_i;
};

generic <typename T>
delegate int Del(T t);

generic <typename T>
delegate int DelV(T% t);

int main() {
   R^ hr = gcnew R(7);
   System::Console::WriteLine((gcnew Del<R^>(&R::f))(hr));

   V v;
   v.m_i = 9;
   System::Console::WriteLine((gcnew DelV<V >(&V::f))(v) );
}

Ausgabe

12
14

Siehe auch

delegate (Komponentenerweiterungen für C++)