Dela via


Gör så här: Definiera och använda ombud (C++/CLI)

Den här artikeln visar hur du definierar och använder delegater i C++/CLI.

Även om .NET Framework innehåller ett antal ombud kan du ibland behöva definiera nya ombud.

I följande kodexempel definieras ett ombud med namnet MyCallback. Händelsehanteringskoden – funktionen som anropas när det här nya ombudet utlöses – måste ha en returtyp av void och ta en String referens.

Huvudfunktionen använder en statisk metod som definieras av SomeClass för att instansiera ombudet MyCallback . Ombudet blir sedan en alternativ metod för att anropa den här funktionen, vilket visas genom att skicka strängen "single" till ombudsobjektet. Därefter länkas ytterligare instanser av MyCallback samman och körs sedan genom ett anrop till delegeringsobjektet.

// 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

Nästa kodexempel visar hur du associerar ett ombud med en medlem i en värdeklass.

// 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

Så här skapar du ombud

Du kan använda operatorn "-" för att ta bort en komponentdelegat från en komponerad delegat.

// 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");
}

Resultat

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

Skicka ett ombud^ till en intern funktion som förväntar sig en funktionspekare

Från en hanterad komponent kan du anropa en intern funktion med funktionspekarparametrar där den interna funktionen sedan kan anropa medlemsfunktionen för den hanterade komponentens ombud.

Det här exemplet skapar .dll som exporterar den inbyggda funktionen:

// 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");
   }
}

Nästa exempel konsumerar .dll och skickar ett delegathandtag till den inbyggda funktionen som förväntar sig en funktionspekare.

// 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
}

Resultat

Call to Managed Function

Att associera delegater med ohanterade funktioner

Om du vill associera ett ombud med en intern funktion måste du omsluta den interna funktionen i en hanterad typ och deklarera funktionen som ska anropas 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;
}

Resultat

hello

Så här använder du obundna ombud

Du kan använda ett obundet ombud för att skicka en instans av den typ vars funktion du vill anropa när ombudet anropas.

Fria delegater är särskilt användbara om du vill iterera genom objekten i en samling – genom att använda nyckelorden for each, in – och anropa en medlemsfunktion på varje instans.

Så här deklarerar, instansierar och anropar bundna och obundna ombud:

Åtgärd Bundna ombud Obundna ombud
Förklara Ombudssignaturen måste matcha signaturen för den funktion som du vill anropa via ombudet. Den första parametern för ombudssignaturen är typen av this för det objekt som du vill anropa.

Efter den första parametern måste delegatsignaturen matcha signaturen för den funktion som du vill anropa via ombudet.
Instansiera När du instansierar ett bundet ombud kan du ange en instansfunktion eller en global eller statisk medlemsfunktion.

För att ange en instansfunktion är den första parametern en instans av den typ vars medlemsfunktion du vill anropa och den andra parametern är adressen till den funktion som du vill anropa.

Om du vill anropa en global eller statisk medlemsfunktion skickar du bara namnet på en global funktion eller namnet på den statiska medlemsfunktionen.
När du instansierar ett obundet ombud skickar du bara adressen till den funktion som du vill anropa.
Ringa När du anropar ett bundet ombud skickar du bara de parametrar som krävs av ombudets signatur. Samma som en bunden delegat, men kom ihåg att den första parametern måste vara en instans av det objekt som innehåller funktionen du vill anropa.

Det här exemplet visar hur du deklarerar, instansierar och anropar obundna ombud:

// 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();
}

Resultat

2
3
2
3
2
7
8
7
8
7

Nästa exempel visar hur du använder obundna delegater och nyckelorden för varje, i för att iterera genom objekt i en samling och anropa en medlemsfunktion på varje instans.

// 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();
}

Det här exemplet skapar en obunden delegat till en egenskaps accessorfunktion:

// 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));
}

Resultat

11

Följande exempel visar hur du anropar ett multicast-ombud, där en instans är bunden och en instans är obunden.

// 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);
}

Resultat

in f(R ^ r)
in f()

Nästa exempel visar hur du skapar och anropar ett obundet allmänt ombud.

// 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) );
}

Resultat

12
14

Se även

delegate (C++ komponenttillägg)