如何从il生成器中调用Action<string, bool>函数

3
在这个示例代码中,我正在尝试从il生成器中调用匿名操作。我不确定如何加载委托的引用以及如何调用它。 如果OnFunctionCall是静态方法而不是属性,则可以做到。
public delegate void TestDelegate();

public static class ExampleOne
{
    public static Action<string, bool> OnFunctionCall
        => (message, flag) => Console.WriteLine("Example");
}

public static class ExampleTwo
{
    public static TType CreateDelegate<TType>(Action<string, bool> onFunctionCall)
        where TType : class
    {
        var method = new DynamicMethod($"{Guid.NewGuid()}", typeof(void), Type.EmptyTypes, typeof(TType), true);

        ILGenerator il = method.GetILGenerator();

        // Emit some code that invoke unmanaged function ...

        // loading the first string argument
        il.Emit(OpCodes.Ldstr, method.Name);

        // not sure here how to load boolean value to the stack
        il.Emit(OpCodes.Ldc_I4_0);

        // this line doesn't work
        // example two has no idea about ExampleOne
        // is it possible to load the reference of the Action<string, bool> to the stack and call it ?
        il.Emit(OpCodes.Call, onFunctionCall.Method);

        il.Emit(OpCodes.Ret);

        return method.CreateDelegate(typeof(TestDelegate)) as TType;
    }
}

public class Program
{
    public static void Main(string[] args)
        => ExampleTwo
            .CreateDelegate<TestDelegate>(ExampleOne.OnFunctionCall)
            .Invoke();
}

使用 CodeDOM 比 Reflection Emit 要容易得多。 - user585968
@MickyD,你能提供一个例子吗? - ptp
@MickyD 它也必须与 Net Standard 2.0 兼容。 - ptp
尝试使用.NET 2的反射和代码DOM,访问链接https://learn.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/using-the-codedom。 - user585968
1个回答

4

您需要传递代表您想要调用的委托所存储的信息。方便的方法是接受一个MemberExpression,否则接受一个MemberInfo也可以。请查看您修改后的代码:

public delegate void TestDelegate();

public static class ExampleOne
{
    public static Action<string, bool> OnFunctionCall
        => (message, flag) => Console.WriteLine("OnFunctionCall");

    public static Action<string, bool> OnFunctionCallField 
        = (message, flag) => Console.WriteLine("OnFunctionCallField");
}

public static class ExampleTwo
{
    public static TType CreateDelegate<TType>(Expression<Func<object>> expression)
        where TType : class
    {
        var body = expression.Body as MemberExpression;
        if (body == null)
        {
            throw new ArgumentException(nameof(expression));
        }

        var method = new DynamicMethod($"{Guid.NewGuid()}", typeof(void), Type.EmptyTypes, typeof(TType), true);

        ILGenerator il = method.GetILGenerator();

        // Get typed invoke method and
        // call getter or load field
        MethodInfo invoke;
        if (body.Member is PropertyInfo pi)
        {
            invoke = pi.PropertyType.GetMethod("Invoke");
            il.Emit(OpCodes.Call, pi.GetGetMethod());
        }
        else if (body.Member is FieldInfo fi)
        {
            invoke = fi.FieldType.GetMethod("Invoke");
            il.Emit(OpCodes.Ldsfld, fi);
        }
        else
        {
            throw new ArgumentException(nameof(expression));
        }

        il.Emit(OpCodes.Ldstr, method.Name);
        il.Emit(OpCodes.Ldc_I4_0);
        il.Emit(OpCodes.Callvirt, invoke);
        il.Emit(OpCodes.Ret);

        return method.CreateDelegate(typeof(TestDelegate)) as TType;
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        ExampleTwo
            .CreateDelegate<TestDelegate>(() => ExampleOne.OnFunctionCall)
            .Invoke();

        ExampleTwo
            .CreateDelegate<TestDelegate>(() => ExampleOne.OnFunctionCallField)
            .Invoke();

        Console.ReadLine();
    }
}

代码正在运行在 .Net Core 2.0 上。


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