尝试从Mono.Cecil引用Task.ContinueWith<T>。

3

问题

我正在尝试使用严格的 Mono.Cecil 获取此 IL 指令。目前,我找到的唯一解决方案涉及导入每个引用程序集及其导出类型,调用 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>)

我可以通过引用获得什么

我想尝试不导入全部内容来完成同样的事情(因此只使用引用),但是做不到。我尝试了两个最接近的方法(也不起作用):

测试1

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

测试2

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>

问题

有什么办法只使用引用就能得到所需的指令吗?

成功(但非常hack-y)的代码

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);

有什么想法吗?

1个回答

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) ;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接