반사를 사용한 이상한 매개 변수 시퀀스
-
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 Addin과 함께 반사기를 사용하고 있습니다.
건배
로한
해결책
당신이 가진 문제는 당신이 정적 방법이 아니라 동적 방법을 호출한다는 것입니다. 생성 된 메소드에는 프로그램 클래스의 인스턴스에 대한 참조가 없습니다.
또한 6 개의 매개 변수 메소드를 위해 7 개의 매개 변수를 스택에 푸시합니다. 첫 번째 매개 변수는 메소드를 호출하는 객체를 참조해야합니다.
당신이보고있는 이상한 동작은 인덱스 6의 매개 변수가 없기 때문에 매개 변수 배열의 시작으로 되돌아 가기 때문일 수 있습니다.
VS 도움말에서 "방법 : 동적 메소드를 정의하고 실행"을 참조하십시오.
메소드 호출에서 객체 매개 변수를 수락하거나 정적으로 만들어 작동 할 수 있습니다.
Public Delegate void testAndler (객체 인스턴스, 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
ㅏstatic
방법 - 논평
gen.Emit(OpCodes.Ldarg_S,6);
- 수정하다
MethodInfo method1 = ...
따라서
하나의 "냄새"는 디버그에서 멈추는 것입니다. Question
방법을 평가할 수 없습니다 this
참조. 그리고 이것은 인스턴스 방법에 대한 것이어야합니다 ... ;-)
편집 : OPS. 나는 Robert Wagner의 답을 내 것보다 훨씬 더 잘 설명했습니다. 필요한 경우 내 게시물을 취소 할 준비가되었습니다 ... :-)