【问题标题】:How do I generate a compiled lambda with method calls?如何使用方法调用生成已编译的 lambda?
【发布时间】:2008-11-26 12:14:44
【问题描述】:

我在运行时为给定成员生成已编译的 getter 方法。现在,我的代码只是假设 getter 方法的结果是一个字符串(非常适合测试)。但是,我想使用我编写的自定义转换器类来完成这项工作,见下文,我添加的“ConverterBase”参考。

我不知道如何将转换器类的调用添加到我的表达式树中。

    public Func<U, string> GetGetter<U>(MemberInfo info)
    {
        Type t = null;
        if (info is PropertyInfo) 
        {
            t = ((PropertyInfo)info).PropertyType;
        }
        else if (info is FieldInfo)
        {
            t = ((FieldInfo)info).FieldType;
        }
        else
        {
            throw new Exception("Unknown member type");
        }

        //TODO, replace with ability to specify in custom attribute
        ConverterBase typeConverter = new ConverterBase();

        ParameterExpression target = Expression.Parameter(typeof(U), "target");
        MemberExpression memberAccess = Expression.MakeMemberAccess(target, info);

        //TODO here, make the expression call "typeConverter.FieldToString(fieldValue)"

        LambdaExpression getter = Expression.Lambda(memberAccess, target);

        return (Func<U, string>)getter.Compile();
    }

我正在寻找在第二个 TODO 区域中放置的内容(我可以处理第一个 :))。

生成的编译 lambda 应该以 U 类型的实例作为参数,调用指定的成员访问函数,然后使用结果调用转换器的“FieldToString”方法,并返回结果字符串。

【问题讨论】:

    标签: c# lambda expression-trees


    【解决方案1】:

    您能否说明您希望表达式评估什么(如果是常规 C#)?我可以很容易地写出这个表达式 - 我只是不完全理解这个问题......

    (编辑重新评论) - 在这种情况下,它会是这样的:

        ConverterBase typeConverter = new ConverterBase();
        var target = Expression.Parameter(typeof(U), "target");
        var getter = Expression.MakeMemberAccess(target, info);
        var converter = Expression.Constant(typeConverter, typeof(ConverterBase));
    
        return Expression.Lambda<Func<U, string>>(
        Expression.Call(converter, typeof(ConverterBase).GetMethod("FieldToString"),
            getter), target).Compile();
    

    或者如果类型拒绝绑定,你需要注入一个强制转换/转换:

        MethodInfo method = typeof(ConverterBase).GetMethod("FieldToString");
        return Expression.Lambda<Func<U, string>>(
            Expression.Call(converter, method,
                Expression.Convert(getter, method.GetParameters().Single().ParameterType)),
                target).Compile();
    

    【讨论】:

    • 完美。奇迹般有效。我遇到了演员阵容问题,但回到这里看到了这个答案......谢谢!
    【解决方案2】:

    您需要将对象包装在 ExpressionConstant 中,例如通过使用 Expression.Constant。这是一个例子:

    class MyConverter
    {
        public string MyToString(int x)
        {
            return x.ToString();
        }
    }
    
    static void Main()
    {
        MyConverter c = new MyConverter();
    
        ParameterExpression p = Expression.Parameter(typeof(int), "p");
        LambdaExpression intToStr = Expression.Lambda(
            Expression.Call(
                Expression.Constant(c),
                c.GetType().GetMethod("MyToString"),
                p),
            p);
    
        Func<int,string> f = (Func<int,string>) intToStr.Compile();
    
        Console.WriteLine(f(42));
        Console.ReadLine();
    }
    

    【讨论】:

    • Expression.Constant - FTW。谢谢。我现在就试一试,如果做得好就奖励胜利。谢谢!
    • 您错过了我的嵌套成员访问调用,但这很容易添加到树中。再次感谢
    • 我没有错过 - 我相信我看到了您的困境并专门解决了这个问题 :) 我在日常工作中从事编译器工作,所以很清楚。
    • 你错过了演员阵容,这让我在给你答案或马克之间产生了分歧……鉴于他包括演员、电话和成员访问权限,我打算按他的方式折腾他们。干杯。
    猜你喜欢
    • 2010-09-17
    • 1970-01-01
    • 2020-04-30
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多