How to convert PropertyInfo to property expression and use it to invoke generic method?

10,394

Solution 1

var entityType = propertyInfo.DeclaringType;
var parameter = Expression.Parameter(entityType, "entity");
var property = Expression.Property(parameter, propertyInfo);
var funcType = typeof(Func<,>).MakeGenericType(entityType, propertyInfo.PropertyType);
var lambda = Expression.Lambda(funcType, property, parameter);

structureConfiguration.GetType()
   .GetMethod("Ignore")
   .MakeGenericMethod(propertyInfo.PropertyType)
   .Invoke(structureConfiguration, new[]{lambda});

Solution 2

Property expressions require the property access to be on a specific object. There's a few options you can take here. First, if this is being done within one of your entity objects, you can simple use a ConstantExpression to build the property expression:

// Already have PropertyInfo in propInfo
Expression.Property(Expression.Constant(this, this.GetType()), propInfo)

However, since you need a Expression<Func<TStructuralType, TProperty>>, then it seems like you're going to have to build it using a ParameterExpression:

ParameterExpression pe = Parameter.Expression(typeof(MyEntity), "eParam");
Expression propExp = Expression.Property(pe, propInfo);

HOWEVER, here's the kicker... This is just a MemberExpression. To convert to the expression you need, you need to use Expression.Lambda to get a Func<> expression of the type you need. The problem? You don't know the type of the property to define the generic parameters of the lambda expression!

Expression<Func<MyEntity, ????>> eFunc = Expression.Lambda<Func<MyEntity, ????>>(propExp, pe);

This is the crux of the problem of doing it this way. That's not to say it can't be done... It's just that using this method IN THIS WAY isn't going to work. You'll have to use a bit runtime and static typing trickery (as well as judicious use of Actions instead of Funcs) to get this to work correctly.

Solution 3

TProperty exists only in the c# source code text. The compiler always resolves it to a concrete type. If you have a method

void Test<T>(T arg)
{
}

and call it like this

Test("hello");
Test(3);

The compiler generates code for two methods!

void Test(string arg)
{
}

void Test(int arg)
{
}

This means that you have to supply concrete types for your generic parameters if you want to have an invokable method.

Share:
10,394
Pol
Author by

Pol

Updated on June 12, 2022

Comments