2012-03-08 12 views
11

Cómo convertir PropertyInfo a la expresión de propiedad que se puede utilizar para invocar el método StructuralTypeConfiguration<TStructuralType>.Ignore<TProperty>(Expression<Func<TStructuralType, TProperty>> propertyExpression)?¿Cómo convertir PropertyInfo a expresión de propiedad y usarlo para invocar el método genérico?

He intentado utilizar para construir Expression.Property() expresión, pero estoy consiguiendo error siguiente cuando se utiliza esta expresión como propertyExpression parámetro:

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

Este error probablemente se refiere a TProperty parámetro de tipo que no sé cómo especificar tener solo PropertyInfo.

Estoy haciendo esto en relación con: Use Entity Framework's StructuralTypeConfiguration.Ignore() to Ignore all properties but specified set.

ACTUALIZACIÓN

Código que no funciona:

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

Debería mostrar el código que no funciona ... –

+0

@JonSkeet - added. – Pol

Respuesta

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

Lo intenté, pero obteniendo 'El tipo o método tiene 1 parámetro (s) genérico (s), pero se proporcionaron 2 argumentos genéricos. Se debe proporcionar un argumento genérico para cada error de parámetro genérico.StackTrace: en System.RuntimeType.SanityCheckGenericArguments (RuntimeType [] genericArguments, RuntimeType [] genericParamters) en System.Reflection.RuntimeMethodInfo.MakeGenericMethod (tipo [] methodInstantiation) en Here_is_this_code (DbModelBuilder modelBuilder) – Pol

+1

Cuando me comentó '.MakeGenericMethod (...) 'Obtuve' Las operaciones de límite tardío no se pueden realizar en los tipos o métodos para los que ContainsGenericParameters es verdadero'. – Pol

+0

prueba la variante actual –

1

TProperty existe sólo en el C# código fuente de texto. El compilador siempre lo resuelve en un tipo concreto. Si usted tiene un método

void Test<T>(T arg) 
{ 
} 

y lo llama como esto

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

El compilador genera código para los dos métodos!

void Test(string arg) 
{ 
} 

void Test(int arg) 
{ 
} 

Esto significa que debe proporcionar tipos concretos para sus parámetros genéricos si desea tener un método invokable.

2

Las expresiones de propiedad requieren que el acceso a la propiedad esté en un objeto específico. Hay algunas opciones que puede tomar aquí. En primer lugar, si esto se está haciendo dentro de uno de sus objetos de entidad, se puede utilizar una sencilla ConstantExpression para construir la expresión de propiedad:

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

Sin embargo, ya que se necesita una Expression<Func<TStructuralType, TProperty>>, entonces parece como si se va a tienen que construir usando un ParameterExpression:

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

Sin embargo, aquí viene lo bueno ... Esto es sólo una MemberExpression. Para convertir a la expresión que necesita, necesita usar Expression.Lambda para obtener una expresión Func <> del tipo que necesita. ¿El problema? ¡No conoce el tipo de propiedad para definir los parámetros genéricos de la expresión lambda!

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

Este es el quid del problema de hacerlo de esta manera. Eso no quiere decir que no se pueda hacer ... Es solo que usar este método DE ESTA MANERA no va a funcionar. Tendrá que usar un bit de tiempo de ejecución y un truco de tipado estático (así como un uso prudente de Acciones en lugar de Funcs) para que esto funcione correctamente.

Cuestiones relacionadas