Поделиться через


Практическое руководство. Определение и использование делегатов (C++/CLI)

В данной статье показано, как определять и использовать делегаты в C++/CLI.

Хотя платформа .NET Framework предоставляет несколько делегатов, иногда может понадобиться задать новые делегатов.

В следующем примере кода определяется с именем MyCallback делегата.Функция - кода обработки событий, которая вызывается при этот новый делегат увольнять- должна иметь тип данных void и иметь ссылку String.

Основная функция использует статический метод SomeClass, определенный для создания делегата MyCallback.Делегат будет алтернативным методом вызов этой функции, как показано, отправляя строка "один" в объект делегата.Следующие дополнительные экземпляры MyCallback, передается как единое целое и затем выполняются одним вызовом объект делегата.

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

Output

  

В следующем примере кода показано, как связать делегат с членом класса.

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

Output

  

Как из делегатов

Можно использовать оператор "-" удаление компонента из делегата структурированного делегата.

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

Output

  
  
  
  
  

Передайте delegate^ в собственную функцию, ожидающую указатель функции

Из управляемого компонента можно вызвать собственная функция с параметрами указателя функции, собственная функция затем может вызывать функцию-член управляемого делегата компонента.

В этом примере создается DLL, который экспортирует собственной функции.

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

В следующем примере используется DLL и передает дескриптор делегата в собственную функцию, ожидающую указатель функции.

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

Output

  

Связывание делегатов с неуправляемыми функциями

Чтобы связать делегат с собственной функцией, необходимо создать собственную функцию в управляемом типе и объявления функция вызывается с помощью 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;
}

Output

  

Использование элемента делегатов

Можно использовать для передачи делегата экземпляр типа функции которого требуется для вызова при вызове делегата.

Для делегатов особенно полезны, если требуется выполнить итерацию по объектам в a коллекция- использованием для каждого внутри слово- и вызов функции-члена на каждом экземпляре.

Описание объявления, создания и вызова границы и несвязанных делегаты.

Действие

Запрещенные делегатов

Для делегатов

Declare

Сигнатура делегата должна соответствовать сигнатуре функции, которую необходимо вызвать через делегат.

Первый параметр сигнатуры делегата тип this для объекта необходимо вызвать.

После первого параметра, сигнатура делегата должна соответствовать сигнатуре функции, которую необходимо вызвать через делегат.

Создать

После создания ограничения делегат, можно определить функцию экземпляра, или глобальных и статической функции-члена.

Для определения функций экземпляра первый параметр экземпляр типа, необходимо вызвать функцию-член, а второй параметр адрес функции, которую необходимо вызвать.

Если необходимо вызвать глобальных и статическая функция-член, просто передать имя функции имя глобальной или статической функции-члена.

При создании экземпляра элемента делегат, просто передайте адрес функции, которую необходимо вызвать.

Call

При вызове делегата ограничения, просто передайте параметры, необходимые сигнатура делегата.

Аналогично ограниченный делегата, но вспоминают, что первый параметр должен быть экземпляром объекта, который содержит функции, которую необходимо вызвать.

В этом примере показан способ объявления, создания и вызова для делегатов.

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

Output

  

В следующем примере кода показано использование элемента делегатов и ключевого слова для каждого внутри для прохождения по объектам в коллекции и вызов функции-члена на каждом экземпляре.

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

В этом примере создается делегат для доступа к функциям свойства:

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

Output

  

В следующем примере показано, как вызвать группового делегата, где один экземпляр ограничен и один экземпляр элемента.

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

Output

  

В следующем примере показано, как создать и вызова несвязанных универсальный метод-делегат.

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

Output

  

См. также

Ссылки

delegate (расширения компонентов C++)