Skip to content

Latest commit

 

History

History
501 lines (383 loc) · 11.3 KB

how-to-define-and-use-delegates-cpp-cli.md

File metadata and controls

501 lines (383 loc) · 11.3 KB
descriptiontitlems.datehelpviewer_keywordsms.assetid
Learn more about: How to: Define and Use Delegates (C++/CLI)
How to: Define and Use Delegates (C++/CLI)
11/04/2016
delegates
1cdf3420-89c1-47c0-b796-aa984020e0f8

How to: Define and Use Delegates (C++/CLI)

This article shows how to define and consume delegates in C++/CLI.

Although the .NET Framework provides a number of delegates, sometimes you might have to define new delegates.

The following code example defines a delegate that's named MyCallback. The event-handling code—the function that's called when this new delegate is fired—must have a return type of void and take a xref:System.String reference.

The main function uses a static method that's defined by SomeClass to instantiate the MyCallback delegate. The delegate then becomes an alternate method of calling this function, as demonstrated by sending the string "single" to the delegate object. Next, additional instances of MyCallback are linked together and then executed by one call to the delegate object.

// use_delegate.cpp// compile with: /clrusingnamespaceSystem; ref classSomeClass { public:staticvoidFunc(String^ str) { Console::WriteLine("static SomeClass::Func - {0}", str); } }; ref classOtherClass { public:OtherClass( Int32 n ) { num = n; } voidMethod(String^ str) { Console::WriteLine("OtherClass::Method - {0}, num = {1}", str, num); } Int32 num; }; delegate voidMyCallback(String^ str); intmain( ) { 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"); return0; }
static SomeClass::Func - single static SomeClass::Func - chained static SomeClass::Func - chained OtherClass::Method - chained, num = 99 OtherClass::Method - chained, num = 100 

The next code sample shows how to associate a delegate with a member of a value class.

// mcppv2_del_mem_value_class.cpp// compile with: /clrusingnamespaceSystem; public delegate voidMyDel(); value classA { public:voidfunc1() { Console::WriteLine("test"); } }; intmain() { A a; A^ ah = a; MyDel^ f = gcnew MyDel(a, &A::func1); // implicit box of af(); MyDel^ f2 = gcnew MyDel(ah, &A::func1); f2(); }
test test 

How to compose delegates

You can use the "-" operator to remove a component delegate from a composed delegate.

// mcppv2_compose_delegates.cpp// compile with: /clrusingnamespaceSystem; delegate voidMyDelegate(String ^ s); ref classMyClass { public:staticvoidHello(String ^ s) { Console::WriteLine("Hello, {0}!", s); } staticvoidGoodbye(String ^ s) { Console::WriteLine(" Goodbye, {0}!", s); } }; intmain() { 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"); }

Output

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

Pass a delegate^ to a native function that expects a function pointer

From a managed component you can call a native function with function pointer parameters where the native function then can call the member function of the managed component's delegate.

This sample creates the .dll that exports the native function:

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

The next sample consumes the .dll and passes a delegate handle to the native function that expects a function pointer.

// delegate_to_native_function_2.cpp// compile with: /clrusingnamespaceSystem;usingnamespaceSystem::Runtime::InteropServices; delegate voidDel(String ^s); public ref classA { public:voiddelMember(String ^s) { Console::WriteLine(s); } }; [DllImportAttribute("delegate_to_native_function", CharSet=CharSet::Ansi)] extern"C"voidnativeFunction(Del ^d); intmain() { A ^a = gcnew A; Del ^d = gcnew Del(a, &A::delMember); nativeFunction(d); // Call to native function }

Output

Call to Managed Function 

To associate delegates with unmanaged functions

To associate a delegate with a native function, you must wrap the native function in a managed type and declare the function to be invoked through PInvoke.

// mcppv2_del_to_umnangd_func.cpp// compile with: /clr #pragma unmanaged extern"C"voidprintf(constchar*, ...); classA { public:staticvoidfunc(char* s) { printf(s); } }; #pragma managed public delegate voidfunc(char*); ref classB { A* ap; public:B(A* ap):ap(ap) {} voidfunc(char* s) { ap->func(s); } }; intmain() { A* a = new A; B^ b = gcnew B(a); func^ f = gcnew func(b, &B::func); f("hello"); delete a; }

Output

hello 

To use unbound delegates

You can use an unbound delegate to pass an instance of the type whose function you want to call when the delegate is called.

Unbound delegates are especially useful if you want to iterate through the objects in a collection—by using for each, in keywords—and call a member function on each instance.

Here's how to declare, instantiate, and call bound and unbound delegates:

ActionBound DelegatesUnbound Delegates
DeclareThe delegate signature must match the signature of the function you want to call through the delegate.The first parameter of the delegate signature is the type of this for the object you want to call.

After the first parameter, the delegate signature must match the signature of the function you want to call through the delegate.
InstantiateWhen you instantiate a bound delegate, you can specify an instance function, or a global or static member function.

To specify an instance function, the first parameter is an instance of the type whose member function you want to call and the second parameter is the address of the function you want to call.

If you want to call a global or static member function, just pass the name of a global function or the name of the static member function.
When you instantiate an unbound delegate, just pass the address of the function you want to call.
CallWhen you call a bound delegate, just pass the parameters that are required by the delegate signature.Same as a bound delegate, but remember that the first parameter must be an instance of the object that contains the function you want to call.

This sample demonstrates how to declare, instantiate, and call unbound delegates:

// unbound_delegates.cpp// compile with: /clr ref structA { A(){} A(int i) : m_i(i) {} voidPrint(int i) { System::Console::WriteLine(m_i + i);} private:int m_i; }; value structV { voidPrint() { System::Console::WriteLine(m_i);} int m_i; }; delegate voidDelegate1(A^, int i); delegate voidDelegate2(A%, int i); delegate voidDelegate3(interior_ptr<V>); delegate voidDelegate4(V%); delegate voidDelegate5(int i); delegate voidDelegate6(); intmain() { A^ a1 = gcnew A(1); A% a2 = *gcnew A(2); Delegate1 ^ Unbound_Delegate1 = gcnew Delegate1(&A::Print); // delegate takes a handleUnbound_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(); }

Output

2 3 2 3 2 7 8 7 8 7 

The next sample shows how to use unbound delegates and the for each, in keywords to iterate through objects in a collection and call a member function on each instance.

// unbound_delegates_2.cpp// compile with: /clrusingnamespaceSystem; ref classRefClass { String^ _Str; public:RefClass( String^ str ) : _Str( str ) {} voidPrint() { Console::Write( _Str ); } }; delegate voidPrintDelegate( RefClass^ ); intmain() { 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() ); foreach ( RefClass^ R in a ) d( R ); Console::WriteLine(); }

This sample creates an unbound delegate to a property's accessor functions:

// unbound_delegates_3.cpp// compile with: /clr ref structB { property int P1 { intget() { return m_i; } voidset(int i) { m_i = i; } } private:int m_i; }; delegate voidDelBSet(B^, int); delegate intDelBGet(B^); intmain() { 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)); }

Output

11 

The following sample shows how to invoke a multicast delegate, where one instance is bound and one instance is unbound.

// unbound_delegates_4.cpp// compile with: /clr ref classR { public:R(int i) : m_i(i) {} voidf(R ^ r) { System::Console::WriteLine("in f(R ^ r)"); } voidf() { System::Console::WriteLine("in f()"); } private:int m_i; }; delegate voidDel(R ^); intmain() { R ^r1 = gcnew R(11); R ^r2 = gcnew R(12); Del^ d = gcnew Del(r1, &R::f); d += gcnew Del(&R::f); d(r2); };

Output

in f(R ^ r) in f() 

The next sample shows how to create and call an unbound generic delegate.

// unbound_delegates_5.cpp// compile with: /clr ref structR { R(int i) : m_i(i) {} intf(R ^) { return999; } intf() { return m_i + 5; } int m_i; }; value structV { intf(V%) { return999; } intf() { return m_i + 5; } int m_i; }; generic <typename T> delegate intDel(T t); generic <typename T> delegate intDelV(T% t); intmain() { 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) ); }

Output

12 14 

See also

delegate (C++ Component Extensions)

close