共用方式為


委派的預設封送處理

根據呼叫的機制,Managed 委派會封送處理為 COM 介面或函式指標:

  • 對於平台叫用,委派預設會封送處理為 Unmanaged 函式指標。

  • 對於 COM Interop,委派預設會封送處理為 _Delegate 型別的 COM 介面。 _Delegate 介面是定義在 Mscorlib.tlb 型別程式庫中,而且包含 Delegate.DynamicInvoke 方法,可以讓您呼叫委派所參考的方法。

下表顯示 Managed 委派資料型別的封送處理選項。 MarshalAsAttribute 屬性提供多個 UnmanagedType 列舉值封送處理委派。

列舉型別

Unmanaged 格式的說明

UnmanagedType.FunctionPtr

Unmanaged 函式指標

UnmanagedType.Interface

_Delegate 型別的介面,如 Mscorlib.tlb 中的定義

請考慮以下的範例程式碼,DelegateTestInterface 的方法是匯出至 COM 型別程式庫。 請注意,只有標示 ref (或 ByRef) 關鍵字的委派 (Delegate) 會做為 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);   
}

型別程式庫表示

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

函式指標可以被解除參考,如同任何其他 Unmanaged 函式指標可以被解除參考一樣。

注意事項注意事項

Unmanaged 程式碼所擁有的 Managed 委派 (Delegate) 之函式指標的參考,無法防止 Common Language Runtime 在 Managed 物件上執行記憶體回收。

例如,下列程式碼是不正確的,因為除了 Test 方法的存留期間之外,cb 物件的參考 (已傳遞給 SetChangeHandler 方法) 無法使 cb 持續作用。 一旦 cb 物件執行記憶體回收,傳遞給 SetChangeHandler 的函式指標將不再有效。

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

為了彌補未預期的記憶體回收,呼叫端必須確保只要 Unmanaged 函式指標正在使用中,cb 物件會持續作用。 如果不再需要函式指標的話,您可以選擇性地擁有告知 Managed 程式碼的 Unmanaged 程式碼,如下列範例所示。

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

請參閱

概念

Blittable 和非 Blittable 型別

方向屬性

複製和 Pin

其他資源

預設的封送處理行為