デリゲートに対する既定のマーシャリング
マネージ デリゲートは、呼び出し機構に基づいて、COM インターフェイスまたは関数ポインタとしてマーシャリングされます。
プラットフォーム呼び出しでは、デリゲートは既定によりアンマネージ関数ポインタとしてマーシャリングされます。
COM 相互運用機能では、デリゲートは既定により _Delegate 型の COM インターフェイスとしてマーシャリングされます。_Delegate インターフェイスは、Mscorlib.tlb タイプ ライブラリで定義されており、Delegate.DynamicInvoke メソッドを含んでいます。このメソッドを使用すると、デリゲートが参照するメソッドを呼び出すことができます。
マネージ デリゲート データ型に対するマーシャリング オプションを次の表に示します。MarshalAsAttribute 属性は、デリゲートをマーシャリングするための UnmanagedType 列挙値をいくつか提供します。
列挙型 | アンマネージ表現の説明 |
---|---|
UnmanagedType.FunctionPtr |
アンマネージ関数ポインタ |
UnmanagedType.Interface |
Mscorlib.tlb で定義されている、_Delegate 型のインターフェイス |
DelegateTestInterface
のメソッドを COM タイプ ライブラリにエクスポートする次のコード例について検討します。キーワード ref (または ByRef) でマークされたデリゲートだけが 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);
};
他の任意のアンマネージ関数ポインタを逆参照できるのと同じように、関数ポインタも逆参照できます。
メモ : |
---|
アンマネージ コードによって保持されるマネージ デリゲートへの関数ポインタを参照する場合、共通言語ランタイムによって該当のマネージ オブジェクトに対してガベージ コレクションが実行されるのは回避できません。 |
たとえば、次のコードは、SetChangeHandler
メソッドに渡される cb
オブジェクトへの参照が、Test
メソッドの有効期間を超えて 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));
}
}
予測不可能なガベージ コレクションに対処するために、呼び出し元は、アンマネージ関数ポインタが使用されている間は cb
オブジェクトを有効な状態に維持する必要があります。オプションとして、次の例に示すように、関数ポインタが不要になったことをアンマネージ コードからマネージ コードに通知することもできます。
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 型
方向属性
コピーと固定