问题
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.
回答1:
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))
来源:https://stackoverflow.com/questions/21732185/member-expression-cannot-convert-to-object-from-nullable-decimal