c# - 如何从带有 MethodCallExpression/lambda 的树中的 ConditionalExpression.IfThen 返回?

标签 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);
}

这是运行时发生的 ArgumentException:

An unhandled exception of type 'System.ArgumentException' occurred in System.Core.dll

Additional information: Expression of type 'System.Void' cannot be used for return type 'System.String'

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

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

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

最佳答案

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

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

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

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

关于c# - 如何从带有 MethodCallExpression/lambda 的树中的 ConditionalExpression.IfThen 返回?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23706697/

相关文章:

c# - 诊断第三方程序集、C# .NET 中的问题

javascript - 使用 asp.net 和母版页在 ListView 中维护回发时的滚动位置

c# - 运行 linq 查询时 DbContext 超时

c# - 在linq中使用之前如何检查null?

linq - Expression.IsFalse 未知?

c# - 使用 linq 时如何最好地清理 SQLDataReader

c# - 当缺少所有表达式时,C# for 循环会做什么。例如 (;;) {}

c# - 使用 LINQ 获取一个 List<> 中的项目,这些项目位于另一个 List<> 中

linq - 如何分配 IQueryable<T> 的属性值?

c# - 有关转换 Func<T,T> 和 Expression<Func<T,T>> 的更多信息