表达式树中的条件方法调用

时间:2015-10-14 19:46:30

标签: c# lambda delegates expression-trees

我试图在我的表达式树中添加一个额外的方法调用,但我对如何实现它略显困惑。以下是我目前正在使用的内容:

Word

我想要发生的是:

1)如果我的SetterInfo对象中的类型名称是ParcelFeat,并且属性名称以' G'开头。我想在valueParameter上调用ConvertParcelFeat,然后在返回时调用ChangeType。

2)如果类型的名称是ParcelFeat以外的任何名称,则调用Changetype正常,但不执行其他步骤

我感到困惑的是如何构建条件。我假设我在上面的代码中执行此操作的方式是错误的,我需要使用Expression.IfThen()之类的东西来构建条件。我也不确定如何将方法调用链接起来。

1 个答案:

答案 0 :(得分:1)

您在Expression.IfThen中不需要,因为对于每个特定的SetterInfo,您只能组合一个特定的lambda实例。

只需在您的ExpressionTree的适当位置插入convertParcelFeatCall,一切都应该正常工作。

所以你的代码可能如下:

class Program
{
    static void Main(string[] args)
    {
        var program = new Program();

        var weightLambda = program.DoInternal("Weight").ToString() 
            == "(Param_0, Param_1) => (Convert(Param_0).Weight = Convert(ChangeType(Param_1, System.Object)))";

        var goodiesLambda = program.DoInternal("Goodies").ToString()
            == "(Param_0, Param_1) => (Convert(Param_0).Goodies = Convert(ChangeType(Param_1, ConvertParcelFeat(Param_1, \"Goodies\"))))";

        Console.WriteLine("WeightLambda is Ok: {0}\nGoodiesLambda is Ok: {1}", weightLambda, goodiesLambda);
    }

    public Action<Object, Object> Do(string name)
    {
        return DoInternal(name).Compile();
    }

    public Expression<Action<object, object>> DoInternal(string name)
    {
        var info = new {Name = name, Type = typeof(Program)};
        var propertyInfo = info.Type.GetProperty(info.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

        var objParameter = Expression.Parameter(typeof(object));
        var valueParameter = Expression.Parameter(typeof(object));

        //This is the method call I'm trying to add
        Expression toBeTypeChanged;
        if (info.Name[0] == 'G' && info.Type.Name == "Program")
        {
            toBeTypeChanged = Expression.Call(ConvertParcelFeatMethod, valueParameter, Expression.Constant(info.Name));
        }
        else
        {
            toBeTypeChanged = Expression.Constant(propertyInfo.PropertyType);
        }

        var changeTypeCall = Expression.Call(ChangeTypeMethod, valueParameter, toBeTypeChanged);

        var objCast = Expression.Convert(objParameter, info.Type);
        var valueCast = Expression.Convert(changeTypeCall, propertyInfo.PropertyType);

        var property = Expression.Property(objCast, propertyInfo);

        var assignment = Expression.Assign(property, valueCast);

        return Expression.Lambda<Action<object, object>>(assignment, objParameter, valueParameter);
    }

    public object Weight { get; set; }
    public object Goodies { get; set; }

    public static object ChangeType(object valueParameter, object constant)
    {
        return null;
    }

    public static object ConvertParcelFeat(object valueParameter, object constant)
    {
        return null;
    }

    public MethodInfo ConvertParcelFeatMethod
    {
        get { return typeof(Program).GetMethod("ConvertParcelFeat"); }
    }

    public MethodInfo ChangeTypeMethod
    {
        get { return typeof(Program).GetMethod("ChangeType"); }
    }
}