如何使用MethodCallExpression/lambda从树中的ConditionalExpression.IfThen返回?

dev*_*ost 5 c# linq expression-trees

我试图让一个表达式树有条件地评估一个字符串.

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

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);
}
Run Code Online (Sandbox Code Playgroud)

这是运行时发生的ArgumentException:

System.Core.dll中发生了未处理的"System.ArgumentException"类型异常

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

我已经发现ConditionalExpression返回"IfFalse"条件的void类型.

这是我的Expression Tree Visualizer的截图: ConditionalExpression返回void

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

kvb*_*kvb 14

更充分地表达你真正想要实现的东西可能会有所帮助(基本上,你想要的表达式树的C#等价物是什么样的).目前,您的表达式树看起来大致相当于:

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

但是,C#编译器不会编译它,因为你没有在任何代码路径上返回一个字符串,所以难怪表达式树没有按你的意愿编译.至少有两个问题:

  1. 你几乎肯定想要使用Expression.Condition而不是Expression.IfThen.这为您提供了... ? ... : ...C#中的语法等价物,这是一个可以用作lambda返回值的表达式.作为一个声明,一个if (...) { }块总是具有void你已经找到的类型(即使你添加了一个也是如此else).
  2. 当你的情况不成立时,你需要弄清楚要做什么.如果你真的需要返回一个字符串,那么你必须要么
    • 选择一些默认的无意义值来返回(例如null或""),或
    • 抛出一个例外