Как преобразовать PropertyInfo в выражение свойства и использовать его для вызова универсального метода?
Как преобразовать PropertyInfo
в выражение свойства, которое можно использовать для вызова StructuralTypeConfiguration<TStructuralType>.Ignore<TProperty>(Expression<Func<TStructuralType, TProperty>> propertyExpression)
?
Я попытался использовать Expression.Property()
для создания выражения, но я получаю следующую ошибку, когда я использую это выражение как параметр propertyExpression
:
The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly.
Эта ошибка, вероятно, относится к параметру типа TProperty
, который я не знаю, как указать только PropertyInfo
.
Я делаю это по отношению к: Используйте Entity Framework StructuralTypeConfiguration.Ignore(), чтобы игнорировать все свойства, но указанный набор.
UPDATE
Код, который не работает:
var propertyInfo = typeof(Foo).GetProperties()[0];
var expression = Expression.Default(typeof(Foo));
var expressionProperty = Expression.Property(expression, propertyInfo);
Ignore(expressionProperty);
Ответы
Ответ 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});
Ответ 2
Выражения свойства требуют, чтобы доступ к свойствам находился на определенном объекте. Здесь есть несколько вариантов. Во-первых, если это выполняется в одном из объектов сущности, вы можете просто использовать ConstantExpression для создания выражения свойства:
// Already have PropertyInfo in propInfo
Expression.Property(Expression.Constant(this, this.GetType()), propInfo)
Однако, поскольку вам нужен Expression<Func<TStructuralType, TProperty>>
, тогда вам кажется, что вам нужно будет создать его с помощью ParameterExpression:
ParameterExpression pe = Parameter.Expression(typeof(MyEntity), "eParam");
Expression propExp = Expression.Property(pe, propInfo);
ОДНАКО, здесь кикер... Это всего лишь MemberExpression. Чтобы преобразовать в нужное выражение, вам нужно использовать Expression.Lambda
, чтобы получить выражение Func < > типа, который вам нужен. Проблема? Вы не знаете тип свойства для определения общих параметров выражения лямбда!
Expression<Func<MyEntity, ????>> eFunc = Expression.Lambda<Func<MyEntity, ????>>(propExp, pe);
В этом суть проблемы этого. Это не значит, что это невозможно сделать... Просто использование этого метода в ЭТОМ ПУТЕ не сработает. Вам нужно будет использовать немного времени выполнения и статическую типизацию (а также разумное использование Actions вместо Funcs), чтобы заставить это работать правильно.
Ответ 3
TProperty
существует только в тексте исходного кода С#. Компилятор всегда разрешает его конкретный тип. Если у вас есть метод
void Test<T>(T arg)
{
}
и назовите его следующим образом
Test("hello");
Test(3);
Компилятор генерирует код для двух методов!
void Test(string arg)
{
}
void Test(int arg)
{
}
Это означает, что вам нужно предоставить конкретные типы для ваших общих параметров, если вы хотите использовать invokable метод.