2010-10-21 8 views
5

Tenemos un código que, dado el nombre de una propiedad, utiliza la reflexión para implementar un Comparador.Dado el nombre de una propiedad, ¿cómo puedo crear un delegado para obtener su valor?

Me gustaría almacenar un delegado/Func para obtener el valor en lugar de pagar el precio de reflexión cada vez que necesitamos obtener un valor.

dado una clase como esta:

public class Person 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
} 

Traté de escribir una función que crearía un delegado para mí

Func<T, object> CreateGetFuncFor<T>(string propertyName) 
{ 
    PropertyInfo prop = typeof(T).GetProperty(propertyName); 

    return (Func<T, object>)Delegate.CreateDelegate(typeof(Func<T, object>), 
                null, 
                prop.GetGetMethod()); 
} 

El siguiente código funciona bien para la Obtención del nombre

var person = new Person { Name = "Dave", Age = 42 }; 

var funcitonToGetName = CreateGetFuncFor<Person>("Name"); 
Console.WriteLine(funcitonToGetName(person)); 

var functionToGetAge = CreateGetFuncFor<Person>("Age"); 

pero para la edad de la edad arroja una ArgumentException con el mensaje "Error vinculante para targ et método "

¿Qué me estoy perdiendo? ¿Hay alguna otra forma de hacerlo?

+0

¡Gracias a ambos Lukes! – Argos

Respuesta

8

Parece extraño que conoce el tipo declarar en tiempo de compilación, pero no el tipo de propiedad. De todos modos ...

Necesitará un paso adicional para convertir el valor de la propiedad en object para que coincida con el tipo de devolución del delegado Func<T,object>. (El paso adicional no es estrictamente necesario para las propiedades de tipo de referencia, pero no causa ningún daño.)

Func<T, object> CreateGetFuncFor<T>(string propertyName) 
{ 
    var parameter = Expression.Parameter(typeof(T), "obj"); 
    var property = Expression.Property(parameter, propertyName); 
    var convert = Expression.Convert(property, typeof(object)); 
    var lambda = Expression.Lambda(typeof(Func<T, object>), convert, parameter); 

    return (Func<T, object>)lambda.Compile(); 
} 
+0

Oh, estoy de acuerdo, pero actualmente no puedo cambiar esas partes del código. – Argos

1

Su probablemente porque la edad se define esencialmente como:

public int Age {get; private set;} 

y un método que devuelve un int no es convertir implícitamente a un método que devuelve un object, mientras que es String.

intento:

Func<T, R> CreateGetFuncFor<T, R>(string propertyName) 
{ 
    PropertyInfo prop = typeof(T).GetProperty(propertyName); 
    return (Func<T, R>)Delegate.CreateDelegate(typeof(Func<T, R>), 
                null, 
                prop.GetGetMethod()); 
} 

y luego

var functionToGetAge = CreateGetFuncFor<Person, int>("Age"); 
+0

Desafortunadamente en el código donde quiero usar esto, no sé de qué tipo se trata la propiedad de antemano. – Argos

+0

¿Qué vas a hacer con Age si no sabes el tipo? ¿Puedes ampliar un poco tu caso de uso? – luke

+0

eventualmente los valores se utilizan en una llamada a System.Collections.Comparer.Default.Compare – Argos

Cuestiones relacionadas