Reputation: 31
I try to make an expression with a PropertyInfo
. The expression should look like:
Expression < Func < PropertyType >>
I need this Expression for this:
https://github.com/aspnet/AspNetCore/blob/8d46b3a64ea784c95dddeb9d421c7cda6de993a2/src/Components/Web/src/Forms/ValidationMessage.cs
The For property needs this kind of Expression.
Can anyone direct me to some links how to get this kind of Expression?
var entity = new Entity;
var propertyInfo = entity.GetType().GetProperty("OneProperty");
var expr = GetExpression(propertyInfo);
// could be:
// Expression<Func<string>> or Expression<Func<int>>
edited;
Upvotes: 2
Views: 1509
Reputation: 112512
If you need a property accessor for a property name given as string, you must also pass it the the object as parameter. Therefore you need an
Expression<Func<Entity, PropertyType>>
This function creates such an expression:
private static LambdaExpression CreatePropertyGetterExpression(Type entityType,
string propertyName)
{
PropertyInfo property = entityType.GetProperty(propertyName);
var parameter = Expression.Parameter(entityType, "e");
var body = Expression.MakeMemberAccess(parameter, property);
return Expression.Lambda(body, parameter);
}
This overload allows you to pass the entity type as generic parameter:
private static LambdaExpression CreatePropertyGetterExpression<TEntity>(string propertyName)
{
return CreatePropertyGetterExpression(typeof(TEntity), propertyName);
}
This test
var expr = CreatePropertyGetterExpression<Entity>("OneProperty");
Console.WriteLine(expr);
Console.WriteLine(expr.GetType());
prints (assuming OneProperty
to be of type int
):
e => e.OneProperty
System.Linq.Expressions.Expression`1[System.Func`2[MyProject.Entity, System.Int32]]
You can get an Expression<Func<PropertyType>>
if you capture a variable like this:
Entity e = new Entity { PropertyOne = 42 };
Expression<Func<int>> expr = () => e.PropertyOne;
But how do you want to capture a variable if you are constructing an expression dynamically? This is not possible.
I found this HtmlHelperValidationExtensions.ValidationMessageFor Method doing what you need:
public static IHtmlContent ValidationMessageFor<TModel,TResult> (
this IHtmlHelper<TModel> htmlHelper,
Expression<Func<TModel,TResult>> expression,
string message,
object htmlAttributes);
You can pass it the Expression<Func<TModel,TResult>>
expression from above! However, you must know the result type in advance. Otherwise you will have to use reflection to call it.
Upvotes: 2
Reputation: 78
I found a solution while trying to bind blazor inputs dynamically:
Entity e = new Entity { PropertyOne = 42 };
Expression<Func<int>> expr = () => e.PropertyOne;
to get the expression for this statement you should use a constant expression:
var e = new Entity() { PropertyOne = 42 };
var property = typeof(Entity).GetProperty("PropertyOne");
var entityType = typeof(Entity);
var parameter = Expression.Constant(e);
var body = Expression.MakeMemberAccess(parameter, property);
var resultToReturn = Expression.Lambda<func<TValue>>(body);
best regards.
Upvotes: 1