Marshalling predefinito per i delegati

Per un delegato gestito, il marshalling viene eseguito come interfaccia COM o puntatore a funzione, in base al meccanismo di chiamata:

  • Con il richiamo piattaforma, per impostazione predefinita il marshalling di un delegato viene eseguito come puntatore a funzione non gestito.

  • Con l'interoperabilità COM, per impostazione predefinita il marshalling di un delegato viene eseguito come interfaccia COM di tipo _Delegate. L'interfaccia _Delegate è definita nella libreria dei tipi Mscorlib.tlb e contiene il metodo Delegate.DynamicInvoke, che consente di chiamare il metodo al quale fa riferimento il delegato.

Nella tabella seguente vengono mostrate le opzioni di marshalling per il tipo di dati del delegato gestito. L'attributo MarshalAsAttribute fornisce numerosi valori dell'enumerazione UnmanagedType per il marshalling di delegati.

Tipo di enumerazione Descrizione del formato non gestito

UnmanagedType.FunctionPtr

Puntatore a funzione non gestito.

UnmanagedType.Interface

Interfaccia di tipo _Delegate, come definito in Mscorlib.tlb.

Nell'esempio riportato di seguito i metodi di DelegateTestInterface sono esportati in una libreria dei tipi COM. Si noti che solo i delegati contrassegnati con la parola chiave ref (o ByRef) vengono passati come parametri 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);   
}

Rappresentazione di libreria dei tipi

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

È possibile annullare i riferimenti a un puntatore a funzione, proprio come per qualsiasi altro puntatore a funzione non gestito.

Nota

Un riferimento al puntatore a funzione di un delegato gestito nel codice non gestito non impedisce l'esecuzione della procedura di Garbage Collection sull'oggetto gestito in Common Language Runtime.

Il codice riportato di seguito, ad esempio, non è corretto, in quanto il riferimento all'oggetto cb, passato al metodo SetChangeHandler, non conserva cb oltre la durata del metodo Test. Una volta che l'oggetto cb viene raccolto nel Garbage Collector, il puntatore a funzione passato a SetChangeHandler non è più valido.

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

Per compensare l'inaspettata operazione di Garbage Collection, il chiamante deve assicurarsi che l'oggetto cb venga mantenuto per tutto il tempo in cui il puntatore a funzione non gestito è in uso. Se lo si desidera, è possibile far sì che il codice non gestito comunichi al codice gestito quando il puntatore a funzione non è più necessario, come nell'esempio riportato di seguito.

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

Vedere anche

Concetti

Tipi copiabili e non copiabili
Attributi direzionali
Copia e blocco

Altre risorse

Comportamento di marshalling predefinito