如何转换Expression <func <t,tproperty =“”>&gt;表达式<func <t,tnewproperty =“”>&gt; </func <t,> </func <t,>

时间:2010-09-06 13:12:18

标签: c# .net lambda expression-trees

以下工作正常,但我的 Body.NodeType 更改为转换,而不是 MemberAccess ,这在获取ModelMetadata.FromLambdaExpression时出现问题:

private Expression<Func<TModel, TNewProperty>> ConvertExpression<TProperty, TNewProperty>(Expression<Func<TModel, TProperty>> expression)
{
    Exression converted = Expression.Convert(expression.Body, typeof(TNewProperty));
    var result =  Expression.Lambda<Func<TModel, TNewProperty>>(converted,    expression.Parameters);
    return result;
}

在ASP.NET MVC 2.0的上下文中,我有自己的EditorFor:

public MvcHtmlString EditorFor<TProperty>(Expression<Func<TModel, TProperty>> expression)

然后,EditorFor会根据元数据在内部将调用委托给特定方法,例如:

public DecimalTextBox DecimalTextBoxFor(Expression<Func<TModel, decimal?>> expression)

DecimalTextBox有一个decimal属性的Value属性,所以我想设置它:

decimalTextBox.Value(expression.Compile()(ViewData.Model));

调用形式编辑器到DecimalTextboxFor不编译因为类型不匹配,这就是我需要转换的原因。

上面的代码,是否进行了转换,但由于Expression.Body.NodeType已更改,因此 ModelMetadata.FromLambdaExpression不起作用,因为表达式类型需要是ArrayIndex,Call,MemberAccess或Parameter。不接受转换。

我的解决方法是将DecimalTextBoxFor更改为:

public DecimalTextBox DecimalTextBoxFor(Expression<Func<TModel, TProperty>> expression)

并转换其中的值:

decimalTextBox.Value((decimal?) Convert.ChangeType(expression.Compile()(ViewData.Model), typeof(decimal?)));

其他部分有效的转换是:

private Expression<Func<TModel, TNewProperty>> ConvertExpression<TProperty, TNewProperty>(Expression<Func<TModel, TProperty>> expression)
{
     Expression<Func<TModel, TNewProperty>> convertedExpression = expression as Expression<Func<TModel, TNewProperty>>;
}

但转换不同的值类型(例如单一到双)当然不起作用。

我希望转换表达本身......

1 个答案:

答案 0 :(得分:1)

不幸的是,如果不更改NodeType的{​​{1}},则无法做到这一点。 Body表达式是一个单独的表达式类型,表示实际操作。为了实现您想要实现的目标,该操作必须是“第一”操作,即表达式树中最顶层的节点。

如果您解释为什么您认为需要Convert保持不变,我可以提供解决方法。在语义上这没有意义:旧表达式的NodeType表示特定操作,而您的新Body表示不同的操作(即,原始操作后跟Body)。您不能指望它代表旧操作,而是返回新操作的结果。