Bagikan melalui


Cara: Menentukan dan Menggunakan Delegasi (C++/CLI)

Artikel ini memperlihatkan cara menentukan dan menggunakan delegasi di C++/CLI.

Meskipun .NET Framework menyediakan sejumlah delegasi, terkadang Anda mungkin harus menentukan delegasi baru.

Contoh kode berikut mendefinisikan delegasi yang bernama MyCallback. Kode penanganan peristiwa—fungsi yang dipanggil saat delegasi baru ini diaktifkan—harus memiliki jenis void pengembalian dan mengambil String referensi.

Fungsi utama menggunakan metode statis yang ditentukan oleh SomeClass untuk membuat instans delegasi MyCallback . Delegasi kemudian menjadi metode alternatif untuk memanggil fungsi ini, seperti yang ditunjukkan dengan mengirim string "tunggal" ke objek delegasi. Selanjutnya, instans MyCallback tambahan ditautkan bersama-sama dan kemudian dijalankan oleh satu panggilan ke objek delegasi.

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

Sampel kode berikutnya menunjukkan cara mengaitkan delegasi dengan anggota kelas nilai.

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

Cara menyusun delegasi

Anda dapat menggunakan operator "-" untuk menghapus delegasi komponen dari delegasi yang terdiri.

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

Hasil

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

Meneruskan delegasi^ ke fungsi asli yang mengharapkan penunjuk fungsi

Dari komponen terkelola, Anda dapat memanggil fungsi asli dengan parameter penunjuk fungsi di mana fungsi asli kemudian dapat memanggil fungsi anggota delegasi komponen terkelola.

Sampel ini membuat .dll yang mengekspor fungsi asli:

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

Sampel berikutnya menggunakan .dll dan meneruskan handel delegasi ke fungsi asli yang mengharapkan penunjuk fungsi.

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

Hasil

Call to Managed Function

Untuk mengaitkan delegasi dengan fungsi yang tidak dikelola

Untuk mengaitkan delegasi dengan fungsi asli, Anda harus membungkus fungsi asli dalam jenis terkelola dan menyatakan fungsi yang akan dipanggil melalui 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;
}

Hasil

hello

Untuk menggunakan delegasi yang tidak terikat

Anda dapat menggunakan delegasi yang tidak terikat untuk meneruskan instans jenis yang fungsinya ingin Anda panggil saat delegasi dipanggil.

Delegasi yang tidak terikat sangat berguna jika Anda ingin melakukan iterasi melalui objek dalam koleksi—dengan menggunakan untuk masing-masing, dalam kata kunci—dan memanggil fungsi anggota pada setiap instans.

Berikut cara mendeklarasikan, membuat instans, dan memanggil delegasi terikat dan tidak terikat:

Perbuatan Delegasi Terikat Delegasi Tidak Terikat
Nyatakan Tanda tangan delegasi harus cocok dengan tanda tangan fungsi yang ingin Anda panggil melalui delegasi. Parameter pertama dari tanda tangan delegasi adalah jenis this untuk objek yang ingin Anda panggil.

Setelah parameter pertama, tanda tangan delegasi harus cocok dengan tanda tangan fungsi yang ingin Anda panggil melalui delegasi.
Instantiate Saat Membuat instans delegasi terikat, Anda dapat menentukan fungsi instans, atau fungsi anggota global atau statis.

Untuk menentukan fungsi instans, parameter pertama adalah instans dari jenis yang fungsi anggotanya ingin Anda panggil dan parameter kedua adalah alamat fungsi yang ingin Anda panggil.

Jika Anda ingin memanggil fungsi anggota global atau statis, cukup berikan nama fungsi global atau nama fungsi anggota statis.
Saat Anda membuat instans delegasi yang tidak terikat, cukup teruskan alamat fungsi yang ingin Anda panggil.
Call Saat Anda memanggil delegasi terikat, cukup berikan parameter yang diperlukan oleh tanda tangan delegasi. Sama seperti delegasi terikat, tetapi ingat bahwa parameter pertama harus berupa instans objek yang berisi fungsi yang ingin Anda panggil.

Sampel ini menunjukkan cara mendeklarasikan, membuat instans, dan memanggil delegasi yang tidak terikat:

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

Hasil

2
3
2
3
2
7
8
7
8
7

Sampel berikutnya menunjukkan cara menggunakan delegasi yang tidak terikat dan untuk masing-masing, dalam kata kunci untuk melakukan iterasi melalui objek dalam koleksi dan memanggil fungsi anggota pada setiap 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();
}

Sampel ini membuat delegasi tidak terikat ke fungsi aksesor properti:

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

Hasil

11

Sampel berikut menunjukkan cara memanggil delegasi multicast, di mana satu instans terikat dan satu instans tidak terikat.

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

Hasil

in f(R ^ r)
in f()

Sampel berikutnya menunjukkan cara membuat dan memanggil delegasi generik yang tidak terikat.

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

Hasil

12
14

Lihat juga

delegasi (Ekstensi Komponen C++)