Cálculo de referencias predeterminado para delegados

Actualización: noviembre 2007

En un delegado administrado las referencias se calculan como una interfaz COM o como un puntero a función, según el mecanismo de llamada:

  • Para la invocación de plataforma, las referencias de un delegado se calculan como un puntero a función no administrado, de forma predeterminada.

  • Para la interoperatividad COM, las referencias de un delegado se calculan como una interfaz COM de tipo _Delegate, de forma predeterminada. La interfaz _Delegate se define en la biblioteca de tipos Mscorlib.tlb y contiene el método Delegate.DynamicInvoke, que permite llamar al método al que hace referencia el delegado.

En la tabla siguiente se muestran las opciones de cálculo de referencias para el tipo de datos de delegado administrado. El atributo MarshalAsAttribute proporciona varios valores de la enumeración UnmanagedType para calcular las referencias de delegados.

Tipo de enumeración

Descripción de formato no administrado

UnmanagedType.FunctionPtr

Puntero a función no administrado.

UnmanagedType.Interface

Interfaz de tipo _Delegate, como se define en Mscorlib.tlb.

Considere el código de ejemplo siguiente en el que los métodos de DelegateTestInterface se exportan a una biblioteca de tipos COM. Observe que sólo los delegados marcados con la palabra clave ref (o ByRef) se pasan como parámetros In/Out.

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

Representación de biblioteca de tipos

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

Se puede anular la referencia de un puntero a función, al igual que con cualquier otro puntero a función no administrado.

Nota:

Una referencia al puntero a función para un delegado administrado que mantiene un código no administrado no impide que Common Language Runtime realice una recolección de elementos no utilizados en el objeto administrado.

Por ejemplo, el código siguiente es incorrecto porque la referencia al objeto cb, pasado al método SetChangeHandler, no mantiene a cb activo más allá de la duración del método Test. Una vez que se recolectan los elementos no utilizados del objeto cb, el puntero a función pasado a SetChangeHandler deja de ser 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 la recolección inesperada de elementos no utilizados, el llamador debe asegurarse de que el objeto cb esté activo mientras se utilice el puntero a función no administrado. Opcionalmente, puede hacer que el código no administrado notifique al código administrado cuando el puntero a función ya no se necesite, como se muestra en el ejemplo siguiente.

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

Vea también

Conceptos

Tipos que pueden o que no pueden representarse como bits o bytes

Atributos direccionales

Copiar y fijar

Otros recursos

Comportamiento predeterminado del cálculo de referencias