Comment : définir et utiliser des délégués (C++/CLI)
Cet article explique comment définir et consommer des délégués en C++/CLI.
Bien que le .NET Framework fournit un certain nombre de délégués, vous devrez peut-être définir de nouveaux délégués.
L’exemple de code suivant définit un délégué nommé MyCallback
. Le code de gestion des événements ( la fonction appelée lorsque ce nouveau délégué est déclenché) doit avoir un type de void
retour et prendre une String référence.
La fonction principale utilise une méthode statique définie par SomeClass
l’instanciation du MyCallback
délégué. Le délégué devient ensuite une autre méthode d’appel de cette fonction, comme illustré par l’envoi de la chaîne « single » à l’objet délégué. Ensuite, d’autres instances sont MyCallback
liées, puis exécutées par un appel à l’objet délégué.
// 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
L’exemple de code suivant montre comment associer un délégué à un membre d’une classe value.
// 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
Guide pratique pour composer des délégués
Vous pouvez utiliser l’opérateur «-
» pour supprimer un délégué de composant d’un délégué composé.
// 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");
}
Sortie
Invoking delegate a:
Hello, A!
Invoking delegate b:
Goodbye, B!
Invoking delegate c:
Hello, C!
Goodbye, C!
Invoking delegate d:
Goodbye, D!
Passer un délégué^ à une fonction native qui attend un pointeur de fonction
À partir d’un composant managé, vous pouvez appeler une fonction native avec des paramètres de pointeur de fonction où la fonction native peut ensuite appeler la fonction membre du délégué du composant managé.
Cet exemple crée le .dll qui exporte la fonction native :
// 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");
}
}
L’exemple suivant utilise le .dll et transmet un handle délégué à la fonction native qui attend un pointeur de fonction.
// 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
}
Sortie
Call to Managed Function
Pour associer des délégués à des fonctions non managées
Pour associer un délégué à une fonction native, vous devez encapsuler la fonction native dans un type managé et déclarer la fonction à appeler via PInvoke
.
// 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;
}
Sortie
hello
Pour utiliser des délégués non liés
Vous pouvez utiliser un délégué indépendant pour passer une instance du type dont vous souhaitez appeler la fonction lorsque le délégué est appelé.
Les délégués non liés sont particulièrement utiles si vous souhaitez itérer au sein des objets d’une collection, à l’aide de chacun, dans des mots clés, et appeler une fonction membre sur chaque instance.
Voici comment déclarer, instancier et appeler des délégués liés et non liés :
Action | Délégués liés | Délégués indépendants |
---|---|---|
Declare | La signature du délégué doit correspondre à la signature de la fonction que vous souhaitez appeler via le délégué. | Le premier paramètre de la signature de délégué est le type de this l’objet que vous souhaitez appeler.Après le premier paramètre, la signature du délégué doit correspondre à la signature de la fonction que vous souhaitez appeler via le délégué. |
Instancier | Lorsque vous instanciez un délégué lié, vous pouvez spécifier une fonction d’instance ou une fonction membre globale ou statique. Pour spécifier une fonction d’instance, le premier paramètre est une instance du type dont vous souhaitez appeler la fonction membre et le deuxième paramètre est l’adresse de la fonction que vous souhaitez appeler. Si vous souhaitez appeler une fonction membre globale ou statique, passez simplement le nom d’une fonction globale ou le nom de la fonction membre statique. |
Lorsque vous instanciez un délégué non lié, transmettez simplement l’adresse de la fonction que vous souhaitez appeler. |
Appeler | Lorsque vous appelez un délégué lié, transmettez simplement les paramètres requis par la signature de délégué. | Identique à un délégué lié, mais n’oubliez pas que le premier paramètre doit être une instance de l’objet qui contient la fonction que vous souhaitez appeler. |
Cet exemple montre comment déclarer, instancier et appeler des délégués non liés :
// 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();
}
Sortie
2
3
2
3
2
7
8
7
8
7
L’exemple suivant montre comment utiliser des délégués non liés et le pour chacun, dans les mots clés pour itérer dans des objets d’une collection et appeler une fonction membre sur chaque instance.
// 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();
}
Cet exemple crée un délégué indépendant aux fonctions d’accesseur d’une propriété :
// 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));
}
Sortie
11
L’exemple suivant montre comment appeler un délégué multidiffusion, où une instance est liée et qu’une instance n’est pas liée.
// 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);
};
Sortie
in f(R ^ r)
in f()
L’exemple suivant montre comment créer et appeler un délégué générique indépendant.
// 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) );
}
Sortie
12
14