Странная последовательность параметров с использованием отражения.Излучать
-
22-07-2019 - |
Вопрос
Я смотрел на отражение.Излучаю недавно.Я написал простую программу, которая генерирует DynamicMethod, который просто вызывает другой метод с теми же параметрами
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Test();
}
public delegate void TestHandler(int a, int b, int c, int d, int e, int f);
public void Test()
{
DynamicMethod method = new DynamicMethod(string.Empty, typeof(void), new[] { typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) }, typeof(Program));
MethodInfo method1 = typeof(Program).GetMethod("Question",BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,null,new Type[]{typeof(Int32),typeof(Int32),typeof(Int32),typeof(Int32),typeof(Int32),typeof(Int32)},null);
MethodInfo method2 = typeof(MethodBase).GetMethod("GetCurrentMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { }, null);
MethodInfo method3 = typeof(Console).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Object) }, null);
ILGenerator gen = method.GetILGenerator();
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Ldarg_S, 0);
gen.Emit(OpCodes.Ldarg_S, 1);
gen.Emit(OpCodes.Ldarg_S, 2);
gen.Emit(OpCodes.Ldarg_S, 3);
gen.Emit(OpCodes.Ldarg_S, 4);
gen.Emit(OpCodes.Ldarg_S, 5);
gen.Emit(OpCodes.Ldarg_S, 6);
gen.Emit(OpCodes.Call, method1);
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Call, method2);
gen.Emit(OpCodes.Call, method3);
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Ret);
TestHandler handler = method.CreateDelegate(typeof(TestHandler)) as TestHandler;
handler(1, 2, 3, 4, 5, 6);
}
public void Question(int a, int b, int c, int d, int e, int f)
{
Console.WriteLine("{0},{1},{2},{3},{4},{5}", a, b, c, d, e, f);
}
}
Когда я запускаю этот пример, я бы ожидал, что он выведет 1,2,3,4,5,6, однако он выводит 2,3,4,5,6,1
Я не слишком уверен, почему...Если вы, ребята, знаете какие-нибудь хорошие ресурсы для использования отражения.Emit не могли бы вы указать мне в этом направлении.Я использовал Reflector с надстройкой Emit.
Ваше здоровье
Рохан
Решение
Проблема, с которой вы столкнулись, заключается в том, что вы вызываете динамический метод, а не статический.Ваш сгенерированный метод не имеет ссылки на экземпляр класса Program.
Также обратите внимание, что вы помещаете 7 параметров в стек для метода с 6 параметрами.Первым параметром должна быть ссылка на объект, для которого вы вызываете метод.
Странное поведение, которое вы видите, может быть связано с отсутствием параметра с индексом 6, и он возвращается к началу массива параметров.
Смотрите раздел "Как:Определение и выполнение динамических методов" в справке VS.
Вы можете заставить его работать, приняв параметр объекта при вызове вашего метода или сделав его статическим:
публичный делегат аннулирует TestHandler (экземпляр объекта, int a, int b, int c, int d, int e, int f);
public void Test()
{
DynamicMethod method = new DynamicMethod(string.Empty, typeof(void), new[] { typeof(object), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) }, typeof(Program));
MethodInfo method1 = typeof(Program).GetMethod("Question", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32), typeof(Int32) }, null);
MethodInfo method2 = typeof(MethodBase).GetMethod("GetCurrentMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { }, null);
MethodInfo method3 = typeof(Console).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Object) }, null);
ILGenerator gen = method.GetILGenerator();
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Ldarg_S, 0);
gen.Emit(OpCodes.Ldarg_S, 1);
gen.Emit(OpCodes.Ldarg_S, 2);
gen.Emit(OpCodes.Ldarg_S, 3);
gen.Emit(OpCodes.Ldarg_S, 4);
gen.Emit(OpCodes.Ldarg_S, 5);
gen.Emit(OpCodes.Ldarg_S, 6);
gen.Emit(OpCodes.Call, method1);
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Call, method2);
gen.Emit(OpCodes.Call, method3);
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Ret);
TestHandler handler = method.CreateDelegate(typeof(TestHandler)) as TestHandler;
handler(this, 1, 2, 3, 4, 5, 6);
}
public void Question(int a, int b, int c, int d, int e, int f)
{
Console.WriteLine("{0},{1},{2},{3},{4},{5}", a, b, c, d, e, f);
}
Другие советы
Чтобы это сработало, вы должны
- сделать
Question
astatic
способ - Комментарий
gen.Emit(OpCodes.Ldarg_S,6);
- изменять
MethodInfo method1 = ...
соответственно
Один "запах" заключается в том, что остановка при отладке на Question
метод, которым вы не можете оценить this
ссылка.И это не должно быть для метода экземпляра...;-)
Редактировать:Оперативный штаб.Я только что увидел ответ Роберта Вагнера, который гораздо лучше объяснен, чем мой.Готов отменить свой пост, если потребуется...:-)