【问题标题】:Conditional method calls in an expression tree表达式树中的条件方法调用
【发布时间】:2015-10-14 19:46:30
【问题描述】:

我正在尝试向我的表达式树添加一个额外的方法调用,但我有点困惑如何实现它。这是我目前正在使用的:

    private static Action<object, object> CreateSetter(SetterInfo info)
    {
        var propertyInfo = info.Type.GetProperty(info.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

        if (propertyInfo == null)
            return (s, v) => { };

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

        //This is the method call I'm trying to add
        if (info.Name[0] == 'G' && info.Type.Name == TaxDataConstant.ParcelFeat)
        {
            var convertParcelFeatCall = Expression.Call(ConvertParcelFeatMethod, valueParameter, Expression.Constant(info.Name));         
        }

        var changeTypeCall = Expression.Call(ChangeTypeMethod, valueParameter, Expression.Constant(propertyInfo.PropertyType));

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

        var lambda = Expression.Lambda<Action<object, object>>(assignment, objParameter, valueParameter);

        return lambda.Compile();
    }

我想要发生的是:

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

2) 如果类型的名称不是 ParcelFeat ,请照常调用 Changetype,无需额外步骤

我很困惑的是如何构建条件。我假设我在上面的代码中这样做的方式是错误的,我需要使用像 Expression.IfThen() 这样的东西来构建条件。我也不确定如何像我想要的那样链接方法调用。

【问题讨论】:

  • Expression.IfThen 中不需要,因为对于每个特定的 SetterInfo,您只需组合一个特定的 lambda 实例
  • 只需将 convertParcelFeatCall 插入 ExpressionTree 的适当位置,一切正常

标签: c# lambda delegates expression-trees


【解决方案1】:

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

只需将 convertParcelFeatCall 插入 ExpressionTree 的适当位置,一切都会正常工作。

所以你的代码可能看起来像:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-24
    • 2020-07-05
    相关资源
    最近更新 更多