如何在单声道cecil中的GenericInstanceType上引用GenericInstanceMethod

时间:2018-04-14 15:33:03

标签: mono.cecil

我想引用的方法定义如下:

class Foo<T1> {
    void Bar<T2>(int value) {...}
}

我的问题与具有通用参数的Foo和Bar相关联 如果我使用

static public GenericInstanceMethod MakeGenericMethod(this MethodReference method, TypeReference[] genericArguments)
{
    var _method = new GenericInstanceMethod(method);
    foreach (var _argument in genericArguments) {
        _method.GenericArguments.Add(genericArguments);
    }
    return _method;
}

生成的代码将引用

Foo<>.Bar<T2>(int)

如果我使用

static public MethodReference Reference(this GenericInstanceType genericInstanceType, MethodReference method)
    _methodReference = new MethodReference(method.Name, _returnType, genericInstanceType) {
        HasThis = method.HasThis,
        ExplicitThis = method.ExplicitThis,
        CallingConvention = method.CallingConvention
    };
    foreach (var parameter in method.Parameters) {
        _methodReference.Parameters.Add(parameter);
    }
    return _methodReference;  
}

生成的代码将引用

Foo<T1>.Bar(int);

两者都是我的期望,但不是我想要的,我找不到将它们组合起来产生正确值的方法

1 个答案:

答案 0 :(得分:0)

您需要从方法引用中创建一个通用实例方法:

using System;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using TypeAttributes = Mono.Cecil.TypeAttributes;

namespace TestGenericMethod
{
    public class Foo<T>
    {
        public void M<X>(X x)
        {
            Console.WriteLine(x);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length > 0)
            {
                var p = new Program();
                p.Test(args[0]);
                return;
            }

            var a = AssemblyDefinition.ReadAssembly(typeof(Program).Assembly.Location);

            var tr = a.MainModule.ImportReference(typeof(Foo<int>));

            var tm = a.MainModule.Types.SingleOrDefault(t => t.Name == "Program").Methods.SingleOrDefault(m => m.Name == "Test");

            var gm = new MethodReference("M", a.MainModule.TypeSystem.Void, tr);
            var genericParameter = new GenericParameter("X", gm);
            gm.GenericParameters.Add(genericParameter);
            gm.Parameters.Add(new ParameterDefinition(genericParameter));
            gm.HasThis = true;
            var mmm = new GenericInstanceMethod(gm);
            mmm.GenericArguments.Add(a.MainModule.TypeSystem.String);

            Console.WriteLine(gm.GetType().FullName);

            var il = tm.Body.GetILProcessor();

            var ret = il.Body.Instructions.SingleOrDefault(i => i.OpCode == OpCodes.Ret);

            il.InsertBefore(ret, il.Create(OpCodes.Ldloc_0));
            il.InsertBefore(ret, il.Create(OpCodes.Ldarg_1));
            il.InsertBefore(ret, il.Create(OpCodes.Callvirt, mmm));

            a.Write("Output.exe");
        }

        private void Test(string s)
        {
            var o = new Foo<int>();
        }
    }
}