2010-10-21 5 views
5

Wir haben Code, der einen Eigenschaftsnamen verwendet, verwendet Reflektion, um einen Comparer zu implementieren.Bei einem gegebenen Eigenschaftsnamen kann ich einen Delegaten erstellen, um seinen Wert zu erhalten

Ich möchte einen Delegierten/Func speichern, um den Wert zu erhalten, anstatt den Reflexionspreis jedes Mal zu zahlen, wenn wir einen Wert erhalten müssen.

eine Klasse wie folgt gegeben:

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

Ich habe versucht, eine Funktion zu schreiben, die einen Delegaten für mich

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

Der folgende Code funktioniert gut für die immer den Namen schaffen würde

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

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

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

, aber für den Altersfaktor gibt es eine ArgumentException mit der Meldung "Fehler beim Binden an targ et method "

Was fehlt mir? Gibt es einen anderen Weg, es zu tun?

+0

Danke an beide Lukes! – Argos

Antwort

8

Es scheint seltsam, dass Sie die Erklärung der Art zur Compile-Zeit, aber nicht die Art der Immobilie wissen. Wie auch immer ...

Sie benötigen einen zusätzlichen Schritt, um den Eigenschaftswert in einen object zu konvertieren, so dass er mit dem Rückgabetyp Func<T,object> des Delegaten übereinstimmt. (Der zusätzliche Schritt ist für referenzierte Eigenschaften nicht unbedingt erforderlich, schadet aber nicht.)

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, ich stimme zu - aber ich kann derzeit nicht diese Teile des Codes ändern. – Argos

1

Es ist wahrscheinlich, weil Alter ist im Wesentlichen wie folgt definiert:

public int Age {get; private set;} 

und ein Verfahren der Rückkehr ein int ein Verfahren nicht implizit konvertierbar ist eine object Rückkehr, während String ist.

Versuch:

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

und dann

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

Leider in dem Code, wo ich das verwenden möchte, weiß ich nicht, welchen Typ die Propery im Voraus ist. – Argos

+0

Was machst du mit Age, wenn du den Typ nicht kennst? Können Sie Ihren Anwendungsfall ein wenig erweitern? – luke

+0

schließlich werden die Werte in einem Aufruf von System.Collections.Comparer.Default.Compare verwendet – Argos

Verwandte Themen