2010-10-21 6 views
5

Nous avons du code qui donne un nom de propriété utilise la réflexion pour implémenter un Comparer.Étant donné un nom de propriété, comment puis-je créer un délégué pour obtenir sa valeur

Je voudrais stocker un délégué/Func pour obtenir la valeur plutôt que de payer le prix de réflexion chaque fois que nous avons besoin d'obtenir une valeur.

donné une classe comme ceci:

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

J'ai essayé d'écrire une fonction qui créerait un délégué pour moi

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()); 
} 

Le code suivant fonctionne très bien pour l'obtention du nom

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

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

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

mais pour la propriété Age, il déclenche une exception ArgumentException avec le message "Error binding to targ et méthode "

Qu'est-ce qui me manque? Y a-t-il un autre moyen de le faire?

+0

Merci à Lukes! – Argos

Répondre

8

Il semble étrange que vous connaissez le type déclarant à la compilation, mais pas le type de propriété. Anyway ...

Vous aurez besoin d'une étape supplémentaire pour convertir la valeur de la propriété en object afin qu'elle corresponde au type de retour du délégué Func<T,object>. (L'étape supplémentaire n'est pas strictement nécessaire pour les propriétés typées par référence, mais ne cause aucun dommage.)

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, je suis d'accord - mais je ne peux pas actuellement modifier ces parties du code. – Argos

1

Son probablement parce que l'âge est essentiellement défini comme:

public int Age {get; private set;} 

et une méthode renvoyant un int est pas implicitement convertible en une méthode renvoyant un object, alors que String est.

essayer:

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()); 
} 

puis

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

Malheureusement, dans le code où je veux utiliser cela, je ne sais pas quel type la propriété est à l'avance. – Argos

+0

Qu'allez-vous faire avec Age si vous ne connaissez pas le type? Pouvez-vous développer un peu votre cas d'utilisation? – luke

+0

éventuellement les valeurs sont utilisées dans un appel à System.Collections.Comparer.Default.Compare – Argos

Questions connexes