我正在尝试使用严格Mono.Cecil
来获取此IL指令。现在,我找到的唯一解决方案涉及导入每个引用程序集及其导出的类型,调用MakeGenericInstanceType()
和Module.Import()
。
它产生的代码是:
call instance class [mscorlib]System.Threading.Tasks.Task`1<!!0> class [mscorlib]System.Threading.Tasks.Task`1<string>::ContinueWith<class MyClass`1<valuetype [mscorlib]System.DateTime>>(class [mscorlib]System.Func`2<class [mscorlib]System.Threading.Tasks.Task`1<!0>, !!0>)
我试图在不导入所有东西的情况下做同样的事情(因此只使用引用),但不能这样做。我做过的两件最接近的事情(并且不起作用)是:
call instance class [mscorlib]System.Threading.Tasks.Task`1<!1> class [mscorlib]System.Threading.Tasks.Task`1<string>::ContinueWith<class MyClass`1<valuetype [mscorlib]System.DateTime>>(class [mscorlib]System.Func`2<class [mscorlib]System.Threading.Tasks.Task`1<!0>, !1>)
问题: !!0
被!1
取代。
call instance class [mscorlib]System.Threading.Tasks.Task`1<class MyClass`1<valuetype [mscorlib]System.DateTime>> class [mscorlib]System.Threading.Tasks.Task`1<string>::ContinueWith<class MyClass`1<valuetype [mscorlib]System.DateTime>>(class [mscorlib]System.Func`2<class [mscorlib]System.Threading.Tasks.Task`1<string>, class MyClass`1<valuetype [mscorlib]System.DateTime>>)
问题:明确定义的所有泛型:
!0
=&gt; string
!!0
=&gt; class MyClass`1<valuetype [mscorlib]System.DateTime>
知道如何只使用引用来获取所需指令吗?
var task = module.GetEverySingleType().First(...);
var returnType = module.GetEverySingleType().First(...);
var continueWith = module.Import((from m in task.GetMethods()
where m.Name == "ContinueWith"
let p = m.GetParameters()
where p.Length == 1 && p[0].ParameterType.Name == "Func`2"
select m.MakeGenericMethod(returnType)).First());
Instruction.Create(OpCodes.Call, continueWith);
GetEverySingleType()
导入每个Assembly,将其加载到内存中,并枚举其类型。
var func = Module.Import(typeof(Func<,>)).MakeGenericType(taskType, returnType);
var continueWith = new GenericInstanceMethod(new MethodReference("ContinueWith", Module.Import(typeof(Task<>)).MakeGenericInstanceType(returnType), taskType) { HasThis = true });
continueWith.GenericArguments.Add(returnType);
continueWith.Parameters.Add(new ParameterDefinition(Module.Import(typeof(Func<,>)).MakeGenericType(taskType, returnType)));
Instruction.Create(OpCodes.Call, continueWith);
有什么想法吗?
答案 0 :(得分:0)
在第二个示例中,您在continueWith
中没有任何通用的参数,这就是为什么生成的方法参考不使用任何参数 的原因。您的目标方法签名使用两个!0
和!!0
。您必须保留通用参数,并且返回/参数类型必须使用它们。您似乎没有从系统程序集导入内容的问题,请尝试以下方法:
var bf = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ;
// import the *generic method* from the *generic type*
// can be done once per module
var cwgg = module.Import (typeof (Task<>).GetMethods (bf).Where (_ =>
_.Name == "ContinueWith" &&
_.IsGenericMethodDefinition &&
_.GetParameters ().Length == 1).Single ()) ;
// close Task<>, keep ContinueWith generic parameter open
var cwgi = new MethodReference (cwgg.Name, cwgg.ReturnType, taskType) ;
cwgi.HasThis = true ;
cwgi.GenericParameters.Add (new GenericParameter ("TNewResult", cwgi)) ;
cwgi.Parameters.Add (new ParameterDefinition (
cwgg.Parameters[0].ParameterType)) ;
// close ContinueWith
var continueWith = new GenericInstanceMethod (cwgi) ;
continueWith.GenericArguments.Add (returnType) ;