Compartilhar via


Padrão de empacotamento de delegados

Um delegado gerenciado é empacotado como uma interface COM ou como um ponteiro de função com base no mecanismo de chamada:

  • Invocação de plataforma, um delegado é empacotado como um ponteiro de função não gerenciada por padrão.

  • Para interoperabilidade COM, um delegado é empacotado como uma interface COM do tipo _Delegate por padrão. O _Delegate interface é definida na biblioteca de tipos de Mscorlib.tlb e contém o Delegate.DynamicInvoke método, que permite que você chame o método que o delegado referências.

A tabela a seguir mostra as opções de empacotamento para o tipo de dados delegado gerenciado. O MarshalAsAttribute atributo fornece vários UnmanagedType valores de enumeração para empacotar delegados.

Tipo de enumeração

Descrição do formato não gerenciado

UnmanagedType.FunctionPtr

Um ponteiro de função não gerenciada.

UnmanagedType.Interface

Uma interface do tipo _Delegate, conforme definido em Mscorlib.tlb.

Considere o seguinte exemplo de código na qual os métodos de DelegateTestInterface são exportadas para uma biblioteca de tipo COM. Observe que apenas delega marcados com o ref (ou ByRef) palavra-chave são passados como In/Out parâmetros.

using System;
using System.Runtime.InteropServices;

public interface DelegateTest {
void m1(Delegate d);
void m2([MarshalAs(UnmanagedType.Interface)] Delegate d);   
void m3([MarshalAs(UnmanagedType.Interface)] ref Delegate d);  
void m4([MarshalAs(UnmanagedType.FunctionPtr)] Delegate d); 
void m5([MarshalAs(UnmanagedType.FunctionPtr)] ref Delegate d);   
}

Representação de biblioteca de tipo

importlib("mscorlib.tlb");
interface DelegateTest : IDispatch {
[id(…)] HRESULT m1([in] _Delegate* d);
[id(…)] HRESULT m2([in] _Delegate* d);
[id(…)] HRESULT m3([in, out] _Delegate** d);
[id()] HRESULT m4([in] int d);
[id()] HRESULT m5([in, out] int *d);
   };

Referência um ponteiro de função pode ser cancelado, assim como referência outro ponteiro de função não gerenciada pode ser cancelado.

Observação

Uma referência para o ponteiro de função para um delegado gerenciado mantido por código não gerenciado não impede que o common language runtime executar coleta de lixo no objeto gerenciado.

Por exemplo, o código a seguir está incorreto porque a referência a cb objeto passado para o SetChangeHandler método, não mantém cb alive além da vida útil da Test método. Uma vez o cb objeto é coletado pelo lixo, o ponteiro de função passado para SetChangeHandler não é mais válida.

public class ExternalAPI {
   [DllImport("External.dll")]
   public static extern void SetChangeHandler(
      [MarshalAs(UnmanagedType.FunctionPtr)]ChangeDelegate d);
}
public delegate bool ChangeDelegate([MarshalAs(UnmanagedType.LPWStr) string S);
public class CallBackClass {
   public bool OnChange(string S){ return true;}
}
internal class DelegateTest {
   public static void Test() {
      CallBackClass cb = new CallBackClass();
      // Caution: The following reference on the cb object does not keep the 
      // object from being garbage collected after the Main method 
      // executes.
      ExternalAPI.SetChangeHandler(new ChangeDelegate(cb.OnChange));   
   }
}

Para compensar a coleta de lixo inesperado, o chamador deve garantir que o cb objeto é mantido em atividade desde que o ponteiro de função não gerenciada está em uso. Opcionalmente, você pode fazer com que o código não gerenciado notificar o código gerenciado quando o ponteiro de função não é mais necessária, como mostra o exemplo a seguir.

internal class DelegateTest {
   CallBackClass cb;
   // Called before ever using the callback function.
   public static void SetChangeHandler() {
      cb = new CallBackClass();
      ExternalAPI.SetChangeHandler(new ChangeDelegate(cb.OnChange));
   }
   // Called after using the callback function for the last time.
   public static void RemoveChangeHandler() {
      // The cb object can be collected now. The unmanaged code is 
      // finished with the callback function.
      cb = null;
   }
}

Consulte também

Conceitos

Blittable e tipos de não-Blittable

Atributos direcionais

Copiando e fixando

Outros recursos

Comportamento de empacotamento padrão