2012-03-08 6 views
11

Jak przekonwertować PropertyInfo na wyrażenie właściwości, które może być użyte do wywołania metody StructuralTypeConfiguration<TStructuralType>.Ignore<TProperty>(Expression<Func<TStructuralType, TProperty>> propertyExpression)?Jak przekonwertować PropertyInfo na wyrażenie właściwości i użyć go do wywołania metody ogólnej?

Próbowałem użyć Expression.Property() skonstruować wyrażenie ale otrzymuję następujący błąd, gdy używam tego wyrażenia jako propertyExpression parametru:

The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly.

Ten błąd prawdopodobnie odnosi się do TProperty typu parametru, który nie wiem jak określić, mając tylko PropertyInfo.

Robię to w odniesieniu do: Use Entity Framework's StructuralTypeConfiguration.Ignore() to Ignore all properties but specified set.

UPDATE

kod, który nie działa:

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

Powinieneś pokazać swój kod, który nie działa ... –

+0

@JonSkeet - dodano. – Pol

Odpowiedz

19
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}); 
+0

Próbowałem, ale otrzymywanie 'Typ lub metoda ma 1 parametr (y) ogólny, ale podano 2 argumenty ogólne. Dla każdego błędu parametru ogólnego należy podać ogólny argument.StackTrace: w System.RuntimeType.SanityCheckGenericArguments (RuntimeType [] genericArguments, RuntimeType [] genericParamters) w System.Reflection.RuntimeMethodInfo.MakeGenericMethod (typ [] methodInstantiation) w Here_is_this_code (DbModelBuilder ModelBuilder) – Pol

+1

Kiedy komentuje '.MakeGenericMethod (...) 'Mam' Operacje Late bound nie mogą być wykonywane na typy lub metody, dla których ContainsGenericParameters jest true. – Pol

+0

wypróbuj aktualny wariant –

1

TProperty istnieje tylko w C# kodu źródłowego tekstu. Kompilator zawsze rozpoznaje konkretny typ. Jeśli masz metoda

void Test<T>(T arg) 
{ 
} 

i nazwać jak ten

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

Kompilator generuje kod dla obu metod!

void Test(string arg) 
{ 
} 

void Test(int arg) 
{ 
} 

Oznacza to, że musisz podać konkretne typy parametrów ogólnych, jeśli chcesz mieć metodę, którą można wybrać.

2

Wyrażenia właściwości wymagają, aby dostęp do właściwości dotyczył określonego obiektu. Jest kilka opcji, które możesz tutaj wybrać. Po pierwsze, jeśli ta jest wykonywana w jednym ze swoich obiektach jednostki, można prosty Użyj ConstantExpression zbudować wyrażenie właściwość:

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

Jednakże, ponieważ trzeba Expression<Func<TStructuralType, TProperty>>, to wydaje się, że masz zamiar trzeba zbudować go za pomocą ParameterExpression:

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

JEDNAK, tutaj jest kopacz ... To jest tylko MemberExpression. Aby przekonwertować na wyrażenie, którego potrzebujesz, musisz użyć Expression.Lambda, aby uzyskać wyrażenie typu, którego potrzebujesz. Problem? Nie znasz typu właściwości, aby zdefiniować ogólne parametry wyrażenia lambda!

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

To jest sedno problemu zrobienia tego w ten sposób. To nie znaczy, że nie da się tego zrobić ... Chodzi o to, że używanie tej metody w TEN SPOSÓB nie zadziała. Będziesz musiał użyć odrobiny sztuczki wykonawczej i statycznego typowania (a także rozsądnego użycia akcji zamiast Funcs), aby to działało poprawnie.