Sdílet prostřednictvím


Standardmäßiges Marshalling für Delegaten

Aktualisiert: November 2007

Verwaltete Delegaten werden als COM-Schnittstellen oder Funktionszeiger gemarshallt. Dieser Vorgang basiert auf dem Aufrufmechanismus:

  • Bei Plattformaufrufen werden Delegaten standardmäßig als nicht verwaltete Funktionszeiger gemarshallt.

  • Bei COM-Interop werden Delegaten standardmäßig als COM-Schnittstellen des _Delegate-Typs gemarshallt. Die _Delegate-Schnittstelle ist in der Typbibliothek Mscorlib.tlb definiert und enthält die Delegate.DynamicInvoke-Methode, mit der Sie die Methode aufrufen können, auf die der Delegat verweist.

In der folgenden Tabelle finden Sie die Optionen zum Marshallen des Datentyps eines verwalteten Delegaten. Das MarshalAsAttribute-Attribut stellt mehrere UnmanagedType-Enumerationswerte zum Marshallen von Delegaten zur Verfügung.

Enumerationstyp

Beschreibung des nicht verwalteten Formats

UnmanagedType.FunctionPtr

Ein nicht verwalteter Funktionszeiger.

UnmanagedType.Interface

Eine Schnittstelle des _Delegate-Typs, wie in Mscorlib.tlb definiert.

Betrachten Sie den folgenden Beispielcode. Hier werden die DelegateTestInterface-Methoden in eine COM-Typbibliothek exportiert. Beachten Sie, dass nur mit dem ref-Schlüsselwort (bzw. dem ByRef-Schlüsselwort) gekennzeichnete Delegaten als In/Out-Parameter übergeben werden.

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

Typbibliothekdarstellung

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

Funktionszeiger können wie alle anderen nicht verwalteten Funktionszeiger dereferenziert werden.

Hinweis:

Ein Verweis auf einen Funktionszeiger, der auf einen in nicht verwaltetem Code enthaltenen verwalteten Delegaten verweist, verhindert nicht, dass die Common Language Runtime die Garbage Collection für das verwaltete Objekt ausführt.

Der folgende Code ist beispielsweise fehlerhaft, weil der Verweis auf das an die SetChangeHandler-Methode übergebene cb-Objekt die Gültigkeit von cb nicht über die Lebensdauer der Test-Methode hinaus aufrechterhält. Sobald für das cb-Objekt eine Garbage Collection durchgeführt wurde, verliert der an SetChangeHandler übergebene Funktionszeiger seine Gültigkeit.

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

Um der unerwarteten Garbage Collection entgegenzuwirken, muss der Aufrufer sicherstellen, dass das cb-Objekt seine Gültigkeit behält, solange der nicht verwaltete Funktionszeiger verwendet wird. Es ist auch möglich, den verwalteten Code durch den nicht verwalteten Code benachrichtigen zu lassen, wenn der Funktionszeiger nicht mehr benötigt wird (siehe folgendes Beispiel).

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

Siehe auch

Konzepte

Blitfähige und nicht blitfähige Typen

Direktionale Attribute

Kopieren und Fixieren

Weitere Ressourcen

Standardmäßiges Marshallingverhalten