Как преобразовать PropertyInfo в выражение свойства и использовать его для вызова универсального метода? - PullRequest
12 голосов
/ 08 марта 2012

Как преобразовать 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.

Я делаю это в отношении: Использование StructuralTypeConfiguration.Ignore () Entity Framework для игнорирования всех свойств, кроме указанного набора .

UPDATE

Код, который не работает:

var propertyInfo = typeof(Foo).GetProperties()[0];
var expression = Expression.Default(typeof(Foo));
var expressionProperty = Expression.Property(expression, propertyInfo);
Ignore(expressionProperty);

Ответы [ 3 ]

21 голосов
/ 08 марта 2012
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 голосов
/ 08 марта 2012

Выражения свойств требуют, чтобы доступ к свойству находился на определенном объекте. Здесь вы можете выбрать несколько вариантов. Во-первых, если это делается внутри одного из ваших объектов сущности, вы можете просто использовать 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);

ОДНАКО, вот кикер ... Это просто выражение члена. Чтобы преобразовать в нужное вам выражение, вам нужно использовать Expression.Lambda, чтобы получить Func <> выражение нужного вам типа. Эта проблема? Вы не знаете тип свойства для определения общих параметров лямбда-выражения!

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

В этом суть проблемы сделать это таким образом. Это не значит, что этого нельзя сделать ... Просто использование этого метода В ЭТОМ СПОСОБЕ не сработает. Вам нужно будет использовать немного хитрости во время выполнения и статической типизации (а также разумное использование Actions вместо Funcs), чтобы заставить это работать правильно.

1 голос
/ 08 марта 2012

TProperty существует только в тексте исходного кода c #.Компилятор всегда разрешает его в конкретный тип.Если у вас есть метод

void Test<T>(T arg)
{
}

и он называется так

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

Компилятор создает код для двух методов!предоставить конкретные типы для ваших общих параметров, если вы хотите иметь вызываемый метод.

...