Yuzlol
Yuzlol

Reputation: 31

PropertyInfo into Expression<Func<PropertyType>>

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

Answers (2)

Olivier Jacot-Descombes
Olivier Jacot-Descombes

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

Mouad Cherkaoui
Mouad Cherkaoui

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

Related Questions