мне необходимо создать DynamicMethod по IL-коду следующего метода:
public int test(string v1, int v2)
{
return (int)call(new object[]{ v1, v2 });
}
где
public object call(object[] args)
{
// что-то возвращающее int
}
Я переписал код из ildasm в ILGenerator.Emit, но при выполнении сгенерированного делегата появляется ошибка недопустимого кода MSIL. Помогите, пожалуйста, создать корректные вызовы ILGenerator.Emit для генерации метода, либо пришлите ссылки на литературу по этому. Заранее благодарю!
Type[] arg_types = new Type[] { typeof(string), typeof(int) };
var dn = new DynamicMethod("myMethod", typeof(int), arg_types);
var il = dn.GetILGenerator();
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4_2);
il.Emit(OpCodes.Newarr, typeof(object));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Box, typeof(int));
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Call, typeof(Form1).GetMethod("call"));
il.Emit(OpCodes.Unbox_Any, typeof(int));
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Br_S);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);
var del = dn.CreateDelegate(typeof(Func<string, int, int>));
del.DynamicInvoke("test",77);
Прямая работа с Reflection.Emit обычно используется в особых случаях, когда нужно сгенерировать сложный многострочный метод. Для однострочного метода, который только вызывает другой метод, можно использовать более простое высокоуровневое средство - деревья выражений. При их использовании не нужно задумываться об отдельных инструкциях и корректности IL. Вот пример, также для более простого случая, когда метод call - статический:
using System;
using System.Collections;
using System.Linq.Expressions;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
public static object call(object[] args)
{
//...
}
static void Main(string[] args)
{
ParameterExpression param1 = Expression.Parameter(typeof(string), "v1");
ParameterExpression param2 = Expression.Parameter(typeof(int), "v2");
NewArrayExpression expr_arr = Expression.NewArrayInit(
typeof(object),
Expression.Convert(param1,typeof(object)),
Expression.Convert(param2, typeof(object))
);
MethodCallExpression call_expr = Expression.Call(typeof(Program).GetMethod("call"), expr_arr);
UnaryExpression conv_expr = Expression.Convert(call_expr, typeof(int));
var f_expr = Expression.Lambda<Func<string, int, int>>(conv_expr, param1,param2);
Func<string, int, int> f = f_expr.Compile();
int res = f("test", 77);
}
}
}
При этом деревья выражений внутри также используют Reflection.Emit и динамические методы. Тип времени выполнения метода f.Method будет System.Reflection.Emit.DynamicMethod+RTDynamicMethod
, он также будет создан в специальной изолированной системной сборке и может быть выгружен сборщиком мусора, когда он больше не нужен.
Ответ лежит рядом. Все комментарии выше верны, но вы создаете динамический метод DynamicMethod
, который не принадлежит ни одному экземпляру класса, к которому принадлежат call() и test(). Это не плохо и не хорошо: ваш метод просто висит в воздухе. То есть ваш emit создает примерно следующее:
class Test{
public static int test(string v1, int v2)
{
return (int)call(new object[]{ v1, v2 });
}
}
class Call{
public object call(object[] args)
{
// что-то возвращающее int
}
}
Такое не скомпилируется
Чтобы обратиться к методу call экземпляра вашего класса необходимо либо загрузить (либо передать) в ваш метод экземпляр класса Call (в вашем случае, это, видимо, Form1
), либо создать динамический метод call подобно тому, как вы создали test, либо сделать call статическим. Последний способ наиболее простой:
class Program
{
static void Main(string[] args)
{
var a = new MyClass().test("d", 5);
Console.WriteLine(a);
Type[] arg_types = new Type[] { typeof(string), typeof(int) };
var dn = new DynamicMethod("myMethod", typeof(int), arg_types, typeof(MyClass));
var il = dn.GetILGenerator();
il.Emit(OpCodes.Ldc_I4_2);
il.Emit(OpCodes.Newarr, typeof(object));
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Box, typeof(int));
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Call, typeof(MyClass).GetMethod("call"));
il.Emit(OpCodes.Unbox_Any, typeof(int));
il.Emit(OpCodes.Ret);
var del = dn.CreateDelegate(typeof(Func<string, int, int>));
var r = del.DynamicInvoke("test", 77);
Console.WriteLine(r);
Console.ReadKey();
}
}
class MyClass
{
public int test(string v1, int v2)
{
var a = call(new object[] { v1, v2 });
return (int)a;
}
public static object call(object[] args)
{
// что-то возвращающее int
return 5;
}
}
Обратите внимание, что я использовал перегрузку DynamicMethod с указанием типа. Согласно документации - это тип, к открытым методам которого динамический метод будет иметь доступ. (скорее всего, myMethod
будет динамически добавлен как статический метод этого типа. Но это не точно. Довольно любопытная штука).
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Не могу добавить объект в CollectionView, которая находится внутри объекта, который находится в ObservableCollectionМного прошерстил интернетов, натыкался...
Никак не могу сообразить как мне правильно сделать реализацию чтобы впихнуть ключ RSA 2048 в шифрование AES
Я пытаюсь сделать SELECT * FROM member WHERE id = 627528083 запрос к базе данных, но мне выдаёт ошибку синтаксиса в строке 41, почему?
Прошу внести ясностьЯ начал изучение с# с консоли что не удивительно