views:

121

answers:

1

The following is working, but my Body.NodeType changes to Convert, instead of MemberAccess which is a problem when getting 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;
}

In the context of a ASP.NET MVC 2.0, I have my own EditorFor:

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

The EditorFor then delegates the call internally, based on metadata, to specific methods, ex:

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

The DecimalTextBox has a Value property of type decimal?, so I want to set it:

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

Call form the EditorFor to the DecimalTextboxFor doesn't compile bacause the types don't match, and that's why I need the conversion.

Above code, does the conversion, but because the Expression.Body.NodeType is changed, the ModelMetadata.FromLambdaExpression doesn't work, because the expression type needs to be an ArrayIndex, Call, MemberAccess or Parameter. Convert is not accepted.

My workaround is changing the DecimalTextBoxFor into:

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

and convert the value inside there:

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

An other conversion that does partially work is:

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

But converting different value types (ex. single to double) doesn't work of course.

I was hoping to convert the Expression itself...

A: 

Unfortunately, this is not possible without changing the NodeType of the Body. The Convert expression is a separate expression type and represents an actual operation. In order to achieve what you are trying to achieve, that operation has to be the “first” operation, i.e. the topmost node in the expression tree.

I might be able to provide a workaround if you explain why you think you need the NodeType to remain the same. Semantically this doesn’t make sense: The Body of the old expression represents a specific operation, and your new Body represents a different operation (namely, the original operation followed by Convert). You can’t expect it to represent the old operation and yet return the result of the new operation.

Timwi