Padrão de marshaling de delegados
Um delegado gerenciado é empacotado sistema autônomo uma interface COM ou sistema autônomo um ponteiro de função, com base no mecanismo de chamada:
Invocação de plataforma, um delegado é empacotado sistema autônomo um ponteiro de função não gerenciada por padrão.
Para interoperabilidade COM, um delegado é empacotado sistema autônomo uma interface COM do tipo _Delegate por padrão.The _Delegate interface é definida na biblioteca de tipos Mscorlib.tlb e contém o Delegate.DynamicInvoke método, que permite que você chame o método que referencia o delegado.
A tabela a seguir mostra as opções de marshaling para o tipo de dados delegado gerenciado.The MarshalAsAttribute atributo fornece vários UnmanagedType valores de enumeração para realizar realizar marshaling 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, sistema autônomo Mscorlib.tlb definidos. |
Considere o seguinte código de exemplo no qual os métodos de DelegateTestInterface são exportadas para uma biblioteca de tipos COM. Observe que apenas delega marcados com o ref (or ByRef) palavra-chave são passados sistema autônomo 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 sistema autônomo referência qualquer Outros ponteiro de função não gerenciada pode ser cancelado.
Observação: |
---|
Uma referência ao ponteiro de função para um delegado gerenciado mantido por código não gerenciado não impede que o common linguagem tempo de execução do executar lixo coleção no objeto gerenciado. |
Por exemplo, o código a seguir é incorreto porque a referência para o cb objeto, passado para o SetChangeHandler método, não mantém. cb Além da vida útil de funcionamento do Test método. Uma vez o cb o objeto é lixo coletado, o ponteiro de função passado para SetChangeHandler não é mais válido.
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 vivo sistema autônomo longo sistema autônomo o ponteiro de função não gerenciada está em uso. Opcionalmente, você pode ter o código não gerenciado notificar o código gerenciado quando o ponteiro de função não é mais necessária, conforme mostrado no 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 Blittable não