Skip to content

Instantly share code, notes, and snippets.

@urasandesu
Created August 2, 2015 01:19
Show Gist options
  • Save urasandesu/e4d4541a4d82a717983f to your computer and use it in GitHub Desktop.
Save urasandesu/e4d4541a4d82a717983f to your computer and use it in GitHub Desktop.
キャストせずにデリゲート A から同じシグネチャのデリゲート B に変換
using System;
using System.Linq;
using System.Reflection.Emit;
namespace ConvertDelegateWithoutCast
{
class Program
{
static void Main(string[] args)
{
// ユーザーが手を入れるコードとプロファイラ側の依存関係を切り離した上で、
// [制限なく AppDomain を超える](http://urasandesu.blogspot.jp/2012/02/appdomain-how-to-use-unmanaged-code-as.html) には、
// 一度 `System.Delegate` にした上で、再び同じシグネチャのデリゲートに戻す必要がある。
{
var dlgt = default(Delegate);
{
var pred = default(Func<int, bool>);
var x = 42;
pred = i => i == x;
dlgt = pred;
}
{
var pred = dlgt.Cast<Predicate<int>>();
Console.WriteLine("Result: {0}", pred(42));
}
}
Console.ReadLine();
}
// 結果 ---
//
// Result: True
//
}
public static class DelegateMixin
{
public static TDelegate Cast<TDelegate>(this Delegate source)
{
if (source == null)
throw new ArgumentNullException("source");
var ctor = typeof(TDelegate).GetConstructors().First();
var converter = new DynamicMethod("Converter", typeof(TDelegate), new[] { typeof(object), typeof(IntPtr) }, typeof(TDelegate).Module);
var gen = converter.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Newobj, ctor);
gen.Emit(OpCodes.Ret);
var @object = source.Target;
var method = source.Method.MethodHandle.GetFunctionPointer();
return ((Func<object, IntPtr, TDelegate>)converter.CreateDelegate(typeof(Func<object, IntPtr, TDelegate>)))(@object, method);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment