からDynamicMethodを作成します。私はDynamicMethodで遊んでと次の操作を行うことを目指しています:アクション<T>指示
私はGetILAsByteArray()
を使用してバイトとしてILコードを取得し、そこからアクションを持っています。このバイトから、私は動的メソッドを作成して実行したいと思います。ここで私が何をしようとしています何の例:
class Program
{
static void Main(string[] args)
{
//Create action and execute
Action<string> myAction = s =>
{
Console.WriteLine("Hello " + s);
};
myAction("World");
//Get IL bytes
byte[] ilBytes = myAction.GetMethodInfo().GetMethodBody().GetILAsByteArray();
DynamicMethod dynamicCallback = new DynamicMethod("myAction", typeof(void), new Type[] { typeof(string) });
DynamicILInfo dynamicIlInfo = dynamicCallback.GetDynamicILInfo();
dynamicIlInfo.SetCode(ilBytes, 100);
dynamicCallback.Invoke(null, new object[] { "World" });
}
}
dynamicCallback.Invoke(null, new object[] { "World" })
我々取得「スロー例外:がmscorlib.dllで 『System.BadImageFormatException』」を呼び出します。
私には分かりませんが、SetCode()
の2番目の引数として使用する必要があるものは、 'maxStackSize'として使用する必要がありますか?最初のアクションと同じ値を設定するにはどうすればよいですか?しかし、これは例外の理由ではないと思います。
ILバイトから動的メソッドを正しく作成するにはどうすればよいですか?
ソリューションここ
私はデュディ東駅で提供完全なソリューションを要約したいと思います:
static void Main(string[] args)
{
Action<string> myAction = s =>
{
Console.WriteLine("Hello " + s);
};
MethodInfo method = myAction.GetMethodInfo();
object target = myAction.Target;
DynamicMethod dm = new DynamicMethod(
method.Name,
method.ReturnType,
new[] {method.DeclaringType}.
Concat(method.GetParameters().
Select(pi => pi.ParameterType)).ToArray(),
method.DeclaringType,
skipVisibility: true);
DynamicILInfo ilInfo = dm.GetDynamicILInfo();
var body = method.GetMethodBody();
SignatureHelper sig = SignatureHelper.GetLocalVarSigHelper();
foreach (LocalVariableInfo lvi in body.LocalVariables)
{
sig.AddArgument(lvi.LocalType, lvi.IsPinned);
}
ilInfo.SetLocalSignature(sig.GetSignature());
byte[] code = body.GetILAsByteArray();
ILReader reader = new ILReader(method);
DynamicMethodHelper.ILInfoGetTokenVisitor visitor = new DynamicMethodHelper.ILInfoGetTokenVisitor(ilInfo, code);
reader.Accept(visitor);
ilInfo.SetCode(code, body.MaxStackSize);
dm.Invoke(target, new object[] { target, "World" });
Console.ReadLine(); //Just to see the result
}
注:DynamicMethodHelperはクラスblog postにハイボ羅によって開発され、説明されているが、直接hereにダウンロードすることもできます。あなたはこのようにそれを行うことができます
私は反射を使ってmaxStackSize値を取得できないと思います。しかし、確かに、それはここで問題ではありません。問題は 'Console.WriteLine'呼び出しがメタデータトークン(おそらくMethodRef)としてエンコードされ、メタデータトークンがそれを宣言するモジュールのスコープ内でのみ有効であることです。 'DynamicILInfo.GetTokenFor'関数を見てみましょう。これらは' DynamicMethod'に有効な他のメタデータ項目と作成トークンをインポートします。 – thehennyy
@thehennyy私は成功していない、私の編集を見てみました。 – Sjoerd222888
ILバイト配列の古いトークンを、新しく作成した 'GetTokenFor'メソッドが返すトークンに置き換える必要があります。 – thehennyy