试图引用Task.ContinueWith<从Mono.Cecil
本文关键字:Mono Cecil ContinueWith 引用 Task | 更新日期: 2023-09-27 17:52:52
问题
我试图得到这个IL指令严格使用Mono.Cecil
。现在,我找到的唯一解决方案涉及导入每个引用程序集及其导出类型,调用MakeGenericInstanceType()
和Module.Import()
。
需要IL指令
生成的代码是:
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>)
我能得到的(仅使用引用)
我试图做同样的事情没有导入一切(因此只使用引用),但不能这样做。我做过的最接近的两件事是:
测试1call 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
=>string
-
!!0
=>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()
导入每个程序集,将其装入内存,并枚举其类型。
不成功的代码(测试2)
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);
任何想法?
在第二个示例中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) ;