2011-11-12 2 views
1

코드에서 반향을 통해 비교 <> 삭제를 만들고 싶습니다. 나는이 있습니다 :즉석에서 비교 <>를 만드는 방법은 무엇입니까?

마지막 줄에 ArgumentException이 발생합니다. MethodInfo는 런타임 MethodInfo 개체 여야합니다. 나는 반성에 처음이고 방출하고, 단지 작은 단계가 빠져있다라고하는 감각을 가지고있다!?

편집 : -

나는 새로운 국회를 만드는 결합 아니에요 나는 또한 DynamicMethod을 시도 :

var returnType = typeof (Int32); 
var parameters = typeof(Comparison<>).GetMethod("Invoke").GetParameters().Select(x => x.ParameterType).ToArray(); 
var handler = new DynamicMethod("", returnType, parameters); 
var generator = handler.GetILGenerator(); 

foreach (var parameter in parameters) 
{ 
    var localVariable = generator.DeclareLocal(parameter); 
    generator.Emit(OpCodes.Ldloc, localVariable); 
} 

if (returnType != null) 
{ 
    var returnValue = generator.DeclareLocal(returnType); 
    generator.Emit(OpCodes.Ldloc, returnValue); 
} 

generator.Emit(OpCodes.Ret); 

handler.CreateDelegate(typeof(Comparison<>)); 

은 BadImageFormatException이 예외 :/


솔루션 :

var returnType = typeof (Int32); 
var methodParameters = typeof(Comparison<>).GetMethod("Invoke").GetParameters().Select(x => x.ParameterType.ToString()).ToArray(); 

AppDomain domain = AppDomain.CurrentDomain; 
AssemblyName aname = new AssemblyName("MyEmissions"); 
AssemblyBuilder assemBuilder = domain.DefineDynamicAssembly(aname, AssemblyBuilderAccess.RunAndSave); 
ModuleBuilder modBuilder = assemBuilder.DefineDynamicModule("MainModule", "MyEmissions.dll"); 

TypeBuilder tb = modBuilder.DefineType("Widget", TypeAttributes.Public); 
MethodBuilder mb = tb.DefineMethod("Echo", MethodAttributes.Public | MethodAttributes.Static); 

GenericTypeParameterBuilder[] typeParameters = mb.DefineGenericParameters(methodParameters); 

mb.SetReturnType(returnType); 
mb.SetParameters(typeParameters); 

ILGenerator gen = mb.GetILGenerator(); 
gen.Emit(OpCodes.Ldnull); 
gen.Emit(OpCodes.Ret); 
var dt = tb.CreateType(); 

var mi = dt.GetMethod("Echo"); 
var gm = mi.MakeGenericMethod(new[] { typeof(string), typeof(string) }); 

var parameter = MulticastDelegate.CreateDelegate(typeof(Comparison<string>), gm); 
+1

I * suspect * 당신은'TypeBuilder.CreateType'을 호출해야합니다. 이처럼 새로운 어셈블리를 만들려면 꼭 * 필요합니까? 나는'DynamicMethod'가 당신에게 더 잘 맞을 것으로 생각합니다. [어떻게 안정적으로 RuntimeMethodInfo하는 MethodBuilder을 변환하는 Reflection.Emit를?] [1] [1] : –

+0

체크 스택 오버 플로우의이 게시물은 당신이 도움이 될 수 http://stackoverflow.com/questions/3031183/reflection -emit-how-to-convert-methodbuilder-to-runtimemethodinfo-reliableably – DeveloperX

+0

방출하려고하는 것의 일부 가짜 C#을 제공 할 수 있습니까? – leppie

답변

2

다른 사람이 이미 코드에서 일부 오류를 지적했습니다. 그러나 또 다른 큰 문제가 있습니다. 일반 메서드 및 바인딩되지 않은 일반 대리자를 만들려고합니다.

DynamicMethod의 경우, you can't create generic method at all. 동적 어셈블리의 경우 가능하지만 DefineGenericParameters()을 사용해야합니다.

어떻게 든 제네릭 메서드를 만들 수 있었다면 언 바운드 제네릭 대리자를 만들 수 없습니다. 즉, 수행하려는 것처럼 Comparison<T> 유형의 대리자를 만들 수 없습니다. T을 특정 유형으로 대체해야합니다. 예를 들어, Comparison<int>을 만들 수 있습니다.

또한 CIL을 사용하면 많은 어려움을 겪을 수 있습니다. Expression을 작성하고이를 컴파일하여 델리게이트를 만드는 것이 훨씬 쉽습니다.

0

두 번째 예를 보자.

당신이하고있는 일이 정확합니다. 하지만 발급 한 코드가 올바르지 않습니다. 그래서 BadImageFormatException을 얻는 것입니다.

현재, 당신은 왼쪽으로 스택에 남아있는 값이 있습니다

generator.Emit(OpCodes.Ldloc, localVariable); 

해결하려면 중 하나를로드하거나 다시 스택에서 그들을 팝 없습니다.

+0

흠 - 스택에 변수를 두는 foreach-loop를 주석 처리하면 BatImageFormatException이 여전히 발생합니다. –

+0

@PapaMufflon, 예외 메시지는 "The signature is incorrect."입니다. 왜냐하면'DynamicMethod'를 사용하여 제네릭 메소드를 생성 할 수 없기 때문입니다.자세한 내용은 내 대답을 참조하십시오. – svick

+0

@svick : 재미있는 :) (답변에 좋은 자리 +1) – leppie