Member Expression cannot convert to object from nullable decimal

asp.net-mvc, c#, linq-expressions

Solution

The problem is that you can't just use `object` as `TProperty` when calling `TextBoxFor<TModel, TProperty>()`. It expects a lambda expression of the form `Func<TModel, TProperty>`, and the variance rules of C# are such that a `Func<TModel, decimal?>` is not assignment compatible with `Func<TModel, object>`. You also can't simply use `Convert()`, because the MVC internals won't accept a lambda whose body is a `Convert` expression.

What you can do is use dynamic binding to invoke `TextBoxFor<TModel, TProperty>()` with the correct type arguments:

public Expression GetParameterByName(PropertyInfo pi)
{
    var fieldName = Expression.Parameter(typeof(RuleViewModel<T>), "x");
    var fieldExpression = Expression.PropertyOrField(
        Expression.Property(fieldName, "RuleModel"),
        pi.Name);
    var exp = Expression.Lambda(
        typeof(Func<,>).MakeGenericType(typeof(RuleViewModel<T>), fieldExpression.Type),
        fieldExpression,
        fieldName);
    return exp;
}

// ...

@InputExtensions.TextBoxFor(Html, (dynamic)Model.GetParameterByName(prop))

Problem

I am working on an MVC project and would like to pass the Html.TextboxFor method the name of a property. This is my viewmodel ``` public class RuleViewModel<T> where T : class, IValidatableObject { private T _rule; public T RuleModel { get { return _rule ?? (_rule = Activator.CreateInstance<T>()); } } public RuleMetadata Metadata { get; set; } public Expression<Func<RuleViewModel<T>, Object>> GetParameterByName(PropertyInfo pi) { var fieldName = Expression.Parameter(typeof(RuleViewModel<T>), "x"); var fieldExpression = Expression.PropertyOrField(Expression.Property(fieldName, "RuleModel"), pi.Name); var exp = Expression.Lambda<Func<RuleViewModel<T>, Object>>(fieldExpression, fieldName); return exp; } } ``` Then in the view I do this ``` @foreach (var prop in Model.RuleModel.GetType().GetProperties()) { var result = Model.Metadata.Columns.SingleOrDefault(m => m.ColumnName == prop.Name); if (result != null) { <td> @Html.TextBoxFor(Model.GetParameterByName(prop)) </td> } } ``` The problem is that when the property is of type decimal?, I get a cannot convert nullable decimal to object error. I looked around and found that you can use Expression.Convert to fix this but when I do that I get an error on the view Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions. Any help would be appreciated. This is a proof of concept project that I'm working on and without this piece it is dead in the water.

Original source