2009-02-24 6 views
7

Betrachten Sie den folgenden Code ein:Kann ich spezifische Metadaten von einem Func <T, object> erhalten?

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" 

Hier ist die Extension-Methode:

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 
} 

Gibt es eine Möglichkeit, dies zu tun? Ich dachte, dass vielleicht diese andere Methode, mit Expression<Func<T, object>> statt Func<T, object> würde mir mehr Kraft zu finden, was ich brauche, aber ich bin ratlos, wie.

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

Dies ist das erste Mal, dass ich etwas so tief mit Linq gemacht habe, also vermisse ich vielleicht etwas Offensichtliches. Grundsätzlich mag ich die Idee, lambdas zu übergeben, so dass ich die Kompilierzeit überprüfe, aber ich weiß nicht, dass meine Idee, wie ich sie in diesem speziellen Fall verwenden kann, funktionieren wird.

Dank

+0

möglich Duplikat von [Get Method Name und Typ mit Lambda-Ausdruck] (http://stackoverflow.com/questions/273941/get-method-name-and-type-using-lambda-ausdruck) – nawfal

Antwort

12

Dies ist die Version, die ich verwende, gibt es eine PropertyInfo zurück, aber den Namen zu bekommen ist 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

Großartig, das war perfekt. Jetzt ist mein Hack komplett! : P Ah, ich hasse es, mit diesen Workarounds zu kommen, um Sachen zur Arbeit zu bringen, "wie es sollte". Ich meine, es macht Spaß und alles, aber einfach zu schmerzhaft, wenn es wirklich Arbeit gibt. Vielen Dank! –

+0

Dies funktioniert nicht mit NULL-fähigen Typen –

3

So etwas sollte es tun:

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

ACHTUNG: Air-Code!

+0

Danke für die Beantwortung Nathan , Ich schätze es. Du warst nahe genug, und da du gesagt hast "so etwas sollte den Trick machen", warst du technisch gesehen nicht falsch! Ich werde die Antwort von @gcores akzeptieren, weil es korrekt war, ohne dass ich Änderungen vornehmen musste. Ich habe dir trotzdem +1 für die Antwort gegeben! –

+0

Es gibt einen kleinen Unterschied zwischen den Antworten von Nathan und gcores in Bezug auf einige Randfälle wie nullbare Dezimalstellen (wenn ich mich richtig erinnere!).Für diese Eigenschaften ist der Body des Ausdrucks keine MemberExpression, sondern eine UnaryExpression (wird in der Antwort von gcores behandelt). –

+0

@Jason Das ist cool, ich hätte seine Antwort akzeptiert, genauso wie sie vollständiger ist als meine. –

6

hier ist eine sehr einfache und schnelle Art und Weise es in diesem Blog zu tun: http://blog.bittercoder.com/PermaLink,guid,206e64d1-29ae-4362-874b-83f5b103727f.aspx

So gegeben:

Func func = Name => "Value";

Sie können die Lambda-Parameter "Name" aus der Funktion Delegierten erhalten, indem Berufung:

func.Method.GetParameters() [0] .Name (zurückkehren würde "Name")

hier ist die überarbeitete Hash-Methode von 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; 
} 

Hoffe, dass es hilft, Patrick

2

nur eine Randnotiz: func.Method.GetParameters() [0] .Name ist extremelly schnell im Vergleich mit dem Lambda-Kompilierung und das Element Ausdruck zu extrahieren, dann dem Mitglied Info, dann dem Namen.