2009-02-24 7 views
7

Consultez le code suivant:Puis-je obtenir des métadonnées spécifiques à partir d'un Func <T, object>?

string propertyName; 
var dateList = new List<DateTime>() { DateTime.Now }; 
propertyName = dateList.GetPropertyName(dateTimeObject => dateTimeObject.Hour); 

// I want the propertyName variable to now contain the string "Hour" 

Voici la méthode d'extension:

public static string GetPropertyName<T>(this IList<T> list, Func<T, object> func) { 
    //TODO: would like to dynamically determine which 
    // property is being used in the func function/lambda 
} 

Est-il possible de le faire? Je pensais que peut-être cette autre méthode, en utilisant Expression<Func<T, object>> au lieu de Func<T, object> me donnerait plus de pouvoir pour trouver ce dont j'ai besoin, mais je suis à une perte de comment.

public static string GetPropertyName<T>(this IList<T> list, Expression<Func<T, object>> expr) { 
    // interrogate expr to get what I want, if possible 
} 

C'est la première fois que j'ai fait quelque chose aussi profond avec Linq, alors peut-être qu'il me manque quelque chose d'évident. Fondamentalement, j'aime l'idée de passer en lambdas, de sorte que je vérifie à la compilation, mais je ne sais pas si mon idée sur la façon dont je peux les utiliser dans ce cas particulier fonctionnera.

Merci

+0

duplication possible de [Obtenir le nom et le type de la méthode en utilisant l'expression lambda] (http://stackoverflow.com/questions/273941/get-method-name-and-type-using-lambda-expression) – nawfal

Répondre

12

Ceci est la version que j'utilise, elle renvoie un PropertyInfo, mais obtenir le nom est trivial.

public static PropertyInfo GetProperty<T>(Expression<Func<T, object>> expression) 
{ 
    MemberExpression memberExpression = null; 

    if (expression.Body.NodeType == ExpressionType.Convert) 
    { 
     memberExpression = ((UnaryExpression) expression.Body).Operand as MemberExpression; 
    } 
    else if (expression.Body.NodeType == ExpressionType.MemberAccess) 
    { 
     memberExpression = expression.Body as MemberExpression; 
    } 

    if (memberExpression == null) 
    { 
     throw new ArgumentException("Not a member access", "expression"); 
    } 

    return memberExpression.Member as PropertyInfo; 
} 
+0

Génial, c'était parfait. Maintenant, mon hack est complet! : P Ah, je déteste avoir à trouver ces solutions de contournement pour que les choses fonctionnent "comme il se doit". Je veux dire, c'est amusant et tout, mais juste trop douloureux quand il y a un vrai travail à faire. Je vous remercie! –

+0

Cela ne fonctionne pas avec les types nullable –

3

Quelque chose comme ça devrait faire l'affaire:

public static string GetPropertyName<T>(this IList<T> list, Expression<Func<T, object>> expr) { 
    MemberExpression member_expression = expr.Body as MemberExpression; 
    if (member_expression == null) 
     throw new ArgumentNullException("member_expression"); 
    MemberInfo member = member_expression.Member; 
    PropertyInfo property = member as PropertyInfo; 
    string proname = memeber.name; 
} 

AVERTISSEMENT: Code aérien!

+0

Merci d'avoir répondu Nathan , Je vous en suis reconnaissant. Vous étiez assez près, et puisque vous avez dit "quelque chose comme ça devrait faire l'affaire", vous n'étiez pas techniquement dans l'erreur! J'accepterai la réponse de @gcores parce que c'était correct sans que je doive faire des changements. Je vous ai quand même donné un +1 pour répondre! –

+0

Theres une différence mineure entre les réponses de Nathan et gcores à l'égard de certains cas marginaux tels que les décimales Nullable (si je me souviens bien!).Pour ces propriétés, le corps de l'expression n'est pas une MemberExpression mais une UnaryExpression (traitée dans la réponse de gcores). –

+0

@Jason C'est cool, j'aurais accepté sa réponse aussi bien qu'elle est plus complète que la mienne. –

6

ici est un moyen très facile et rapide à faire sur ce blog: http://blog.bittercoder.com/PermaLink,guid,206e64d1-29ae-4362-874b-83f5b103727f.aspx

donc donné:

Func func = Name => "Valeur";

Vous pouvez obtenir le paramètre lambda "Nom" du délégué de la fonction par appel:

func.Method.GetParameters() [0] .name (renverrait "Name")

Voici la méthode Hash révisée de Andrey:

public Dictionary<string, T> Hash<T>(params Func<string, T>[] args) 
where T : class 
{ 
    var items = new Dictionary<string, T>(); 
    foreach (var func in args) 
    { 
     var item = func(null); 
     items.Add(func.Method.GetParameters()[0].Name, item); 
    } 
    return items; 
} 

Hope it helps, Patrick

2

Juste une remarque: func.Method.GetParameters() [0] .name est extremelly rapide par rapport à la compilation du lambda et l'extraction de l'expression de membre, puis l'info membre, le nom.