2008-09-21 23 views
5

Ich muss eine Funktion schreiben, die eine Eigenschaft als Parameter empfängt und ihren Getter ausführt.Wie eine generische Eigenschaft als Parameter an eine Funktion übergeben?

Wenn ich brauchte eine Funktion/Delegate übergeben Ich habe verwendet würde:

delegate RET FunctionDelegate<T, RET>(T t); 

void func<T, RET>(FunctionDelegate function, T param, ...) 
{ 
    ... 
    return function.Invoke(param); 
} 

Gibt es eine ähnliche Art und Weise eine Eigenschaft zu definieren, so dass ich es Getter und/oder Setter im Funktionscode aufrufen könnte?

Antwort

7

Sie können Reflection verwenden, Sie können ein MethodInfo-Objekt für die get/set-Zugriffsmethoden abrufen und es als Invoke-Methode aufrufen.

Das Codebeispiel vorausgesetzt, dass Sie beide haben eine Get- und Set-Zugriffs- und Sie wirklich hinzuzufügen, haben die Fehlerbehandlung, wenn Sie dies im Produktionscode verwenden möchten:

Zum Beispiel den Wert der Eigenschaft Foo des Objekts obj zu erhalten Sie können schreiben:

value = obj.GetType().GetProperty("Foo").GetAccessors()[0].Invoke(obj,null); 

es setzen:..

obj.GetType().GetProperty("Foo").GetAccessors()[1].Invoke(obj,new object[]{value}); 

So können Sie obj.GetType() GetProperty ("Foo") GetAccessors() [0], um Ihre Methode übergeben und Führen Sie die Invoke-Methode aus.

ein einfacher Weg ist anonyme Methoden zu verwenden (dies in .net 2.0 oder höher arbeiten), lassen Sie sich eine leicht modifizierte Version des Codes verwenden, zB:

delegate RET FunctionDelegate<T, RET>(T t); 

void func<T, RET>(FunctionDelegate<T,RET> function, T param, ...) 
{ 
    ... 
    return function(param); 
} 

für eine Eigenschaft mit dem Namen Foo vom Typ int das ist Teil einer Klasse Someclass:

SomeClass obj = new SomeClass(); 
func<SomeClass,int>(delegate(SomeClass o){return o.Foo;},obj); 
3

Eigenschaften sind einfach syntaktischer Zucker für Methoden.

Ich glaube nicht, dass Sie eine Eigenschaft so ändern können, dass sie zu einer Entität wird, "deren Getter Sie aufrufen können".

Sie können jedoch eine Methode GetPropertyValue() erstellen und diese übergeben, als wäre es ein Delegat.

+1

Das ist eine sehr gute Idee, auf dem KISS-Prinzip ist. Leider kann ich es an dieser Stelle nicht verwenden :( Das Problem ist, dass die Eigenschaft, die ich verwende, nicht Teil meines Codes ist. Und das Schreiben eines Wrappers fügt einen Overhead hinzu, den ich an dieser Stelle nicht möchte –

2

@Dror Helfer,

Ich fürchte, Sie können es auf diese Weise nicht tun. Der Compiler generiert Methoden get_PropertyName und set_PropertyName, auf die jedoch ohne Reflection nicht zugegriffen werden kann. IMO besten Sie können tun, erstellen Sie eine Funktion, die System.Reflection.ProperyInfo und System.Object Params und returns propInfo.GetValue (obj, null);

1

Re: aku Antwort:

Dann müssen Sie zuerst die Eigenschaft info erhalten. Es scheint, dass "Use Reflection" die Standardantwort auf die härteren C# -Fragen ist, aber die Reflektion liefert nicht ganz so schwer zu wartenden Code. Dror, warum nicht einfach einen Delegaten erstellen, der die Eigenschaft für Sie liest? Es ist ein einfacher One-Liner und ist wahrscheinlich die schnellste und schönste Lösung für Ihr Problem.

+0

Ja, die Lösung wird Reflection sowieso beinhalten Sie können einige hilfreiche Wrapper erstellen, aber ich bevorzuge einfacheren Code Die Praxis zeigt, dass komplexe Reflektionslösungen sehr zerbrechlich sind – aku

+1

Martijn - Ich habe Sie bereits bezüglich der Erstellung eines Wrappers beantwortet - obwohl es eine einfache Lösung ist, ist es nicht das, was ich brauche –

11

Sie können auch so etwas wie schreiben:

static void Method<T, U>(this T obj, Expression<Func<T, U>> property) 
     { 
      var memberExpression = property.Body as MemberExpression; 
      //getter 
      U code = (U)obj.GetType().GetProperty(memberExpression.Member.Name).GetValue(obj, null); 
      //setter 
      obj.GetType().GetProperty(memberExpression.Member.Name).SetValue(obj, code, null); 
     } 

und Beispiel des Aufrufs:

DbComputerSet cs = new DbComputerSet(); 
cs.Method<DbComputerSet, string>(set => set.Code); 
+0

Es gibt auch die Möglichkeit einer UnaryExpression, die Sie berücksichtigen müssen: http://stackoverflow.com/a/2916344/265877 – Alex

Verwandte Themen