Como definir e usar delegados (C++/CLI)

Este artigo mostra como definir e consumir representantes em C++/CLI.

Embora o .NET Framework fornecesse um número de delegados às vezes, talvez você precise definir novos representantes.

O exemplo de código a seguir define um delegado que é chamado MyCallback.A função do código - o manipulador de eventos que é chamado quando esse novo delegado é acionar- deve ter um tipo de retorno de void e receber uma referência de String .

A função principal usa um método estático que é definido por SomeClass para criar uma instância do representante de MyCallback .O representante transformações em um método alternativo de chamar essa função, conforme demonstrado enviando a cadeia de caracteres “única” ao objeto delegado.Em seguida, instâncias adicionais de MyCallback são ligados juntos e executado em seguida por uma chamada ao objeto delegado.

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

Saída

  

O exemplo de código a seguir mostra como associar um delegado com um membro de uma classe de valor.

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

Saída

  

Como composto representantes

Você pode usar o operador de “-” para remover um representante componente de um delegado composto.

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

Saída

  
  
  
  
  

Passar um delegate^ a uma função nativo que espera um ponteiro de função

De um componente gerenciado você pode chamar uma função nativo com parâmetros ponteiro de função onde a função nativo em pode chamar a função de membro de representante gerenciado do componente.

Este exemplo cria o arquivo .dll que exportar a função nativo:

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

O exemplo a seguir consome o arquivo .dll e passa um identificador do delegado a função nativo que espera um ponteiro de função.

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

Saída

  

Para associar representantes com funções não gerenciados

Para associar um delegado com uma função nativo, você deve encapsular a função nativo em um tipo gerenciado e declarar a função para ser chamada com 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;
}

Saída

  

Para usar delegados desatados

Você pode usar um representante desatado para passar uma instância do tipo cujo papel você deseja chamar quando o representante é chamado.

Delegados desatados são especialmente úteis se você quiser percorrer os objetos na coleção por usar para cada um, em a palavras-chave e para chamar uma função de membro em cada instância.

É aqui como declarar, criar uma instância de, e chamar o limite e representantes desatados:

Ação

Delegados limitados

Delegados desatados

Declare

A assinatura do representante deve coincidir com a assinatura de função que você deseja chamar pelo delegado.

O primeiro parâmetro da assinatura do representante é o tipo de this para o objeto que você deseja chamar.

Após o primeiro parâmetro, a assinatura do representante deve coincidir com a assinatura de função que você deseja chamar pelo delegado.

Criar uma instância

Quando você cria uma instância de um representante associado, você pode especificar uma função de instância, ou uma função de membro estático ou global.

Para especificar uma função de instância, o primeiro parâmetro é uma instância do tipo cuja função de membro você deseja chamar e o segundo parâmetro é o endereço da função que você deseja chamar.

Se você deseja chamar uma função de membro estático ou global, passe apenas o nome de uma função global ou o nome da função de membro estático.

Quando você cria uma instância de um delegado desatado, passe apenas o endereço da função que você deseja chamar.

Call

Quando você chama um representante associado, basta passar parâmetros que são exigidos pela assinatura do representante.

Mesmo que um representante associado, mas lembram que o primeiro parâmetro deve ser uma instância do objeto que contém a função que você deseja chamar.

Este exemplo demonstra como declarar, para criar uma instância de, e para chamar desatou representantes:

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

Saída

  

O exemplo a seguir mostra como usar delegados desatados e as palavras-chave de para cada um, em para percorrer os objetos em uma coleção e para chamar uma função de membro em cada instância.

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

Este exemplo cria um delegado desatado funções de acesso de uma propriedade:

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

Saída

  

O exemplo a seguir mostra como chamar um destino multicast, onde uma instância é delimitado e uma instância é desatada.

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

Saída

  

O exemplo a seguir mostra como criar e chamar um delegado genérico desatado.

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

Saída

  

Consulte também

Referência

delegado (Extensões de Componentes C++)