【问题标题】:How to return from ConditionalExpression.IfThen in tree with MethodCallExpression / lambda?如何使用 MethodCallExpression / lambda 从 ConditionalExpression.IfThen 中返回?
【发布时间】:2014-05-17 01:22:17
【问题描述】:

我正在尝试让表达式树有条件地计算为字符串。

到目前为止,这是我的代码:

IQueryable<Category> myCategories = DataUtil.Categories.AsQueryable();

ParameterExpression categoryParameterExpression = Expression.Parameter(typeof (Category), "category");
MemberExpression categoryNameMemberExpression = Expression.PropertyOrField(categoryParameterExpression, "CategoryName");
MemberExpression categoryNameLengthExpression = Expression.Property(categoryNameMemberExpression, typeof (string).GetProperty("Length"));
ConstantExpression constantLengthExpression = Expression.Constant(10, typeof (int));
BinaryExpression greaterThanLengthExpression = Expression.GreaterThan(categoryNameLengthExpression, constantLengthExpression);
var getNameInCapsMethod = typeof (Category).GetMethod("GetNameInCaps", BindingFlags.Instance | BindingFlags.Public);
MethodCallExpression getNameInCapsExpression = Expression.Call(categoryParameterExpression, getNameInCapsMethod, categoryNameMemberExpression);

ConditionalExpression ifGreaterThanLengthGetUpperNameExpression = Expression.IfThen(greaterThanLengthExpression, getNameInCapsExpression); 

// I need something between the lambda and the ConditionalExpression to ensure that the void type is not returned?

var ifGreaterThanLengthGetUpperNameLambdaExpression = Expression.Lambda<Func<Category, string>>(ifGreaterThanLengthGetUpperNameExpression, new ParameterExpression[] { categoryParameterExpression }); 
foreach (var category in myCategories)
{
    var upperName = ifGreaterThanLengthUpperLambda(category);
    System.Windows.MessageBox.Show(upperName);
}

这是运行时发生的 ArgumentException:

“System.ArgumentException”类型的未处理异常发生在 System.Core.dll

附加信息:“System.Void”类型的表达式不能 用于返回类型'System.String'

我发现 ConditionalExpression 正在为“IfFalse”条件返回 void 类型。

这是我的 Expression Tree Visualizer 的屏幕截图:

我只想要字符串值。我意识到 ConditionalExpression 类型上有一个 Expression.IfThenElse,但我不确定在 Else 表达式中放入什么。 (如果可能的话,我不想只传回一个空字符串。)有没有办法让我确保仅在前面的 BinaryExpression 评估为真时才评估条件?无论如何,我该如何解决这个问题?

【问题讨论】:

    标签: c# linq expression-trees


    【解决方案1】:

    更全面地表达您真正想要实现的目标可能会有所帮助(本质上,您想要的表达式树的 C# 等效项会是什么样子)。目前,您的表达式树大致相当于这样:

    Func<Category, string> f = (category) => { 
        if (category.CategoryName.Length > 10) {
            category.GetNameInCaps(category.CategoryName);
        }
    };
    

    但是,C# 编译器不会编译它,因为您没有在任何代码路径上返回字符串,因此表达式树没有按照您的意愿编译也就不足为奇了。至少有两个问题:

    1. 您几乎肯定希望使用Expression.Condition 而不是Expression.IfThen。这为您提供了相当于 C# 中的 ... ? ... : ... 语法,这是一个可用作 lambda 的返回值的表达式。作为声明,if (...) { } 块始终具有 void 类型,正如您所发现的(即使您添加了 else,这也是正确的)。
    2. 您需要弄清楚当您的条件不成立时该怎么做。如果你真的需要返回一个字符串,那么你必须要么
      • 选择一些默认的无意义值返回(例如null""),或者
      • 抛出异常

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-21
      • 2015-08-27
      • 1970-01-01
      • 2023-01-10
      • 1970-01-01
      • 2019-08-21
      • 2021-10-23
      • 1970-01-01
      相关资源
      最近更新 更多