2008-09-21 10 views
5

Je dois écrire une fonction qui reçoit une propriété en tant que paramètre et exécuter son getter.Comment passer une propriété générique en tant que paramètre à une fonction?

Si je devais passer une fonction/délégué, je l'aurais utilisé:

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

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

Y at-il une manière similaire à définir une propriété pour que je puisse l'invoquer est getter et/ou setter dans le code de fonction?

Répondre

7

Vous pouvez utiliser la réflexion, vous pouvez obtenir un objet MethodInfo pour les accesseurs get/set et appeler sa méthode Invoke.

L'exemple de code suppose que vous avez à la fois la manipulation d'un accesseurs get et set et vous avez vraiment ajouter erreur si vous voulez utiliser dans le code de production:

Par exemple, pour obtenir la valeur de la propriété Foo d'objet obj vous pouvez écrire:

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

pour le définir:..

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

vous pouvez donc passer obj.GetType() GetProperty ("Foo") GetAccessors() [0] à votre méthode et exécute sa méthode Invoke.

un moyen plus facile est d'utiliser des méthodes anonymes (cela fonctionnera dans .net 2.0 ou version ultérieure), nous allons utiliser une version légèrement modifiée de votre exemple de code:

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

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

pour une propriété nommée Foo de type int qui fait partie d'un SomeClass de classe:

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

Les propriétés sont simplement du sucre syntaxique pour les méthodes.

Je ne pense pas que vous pouvez modifier une propriété de sorte qu'elle devienne une entité "dont vous pouvez appeler le getter".

Vous pouvez cependant créer une méthode GetPropertyValue() et la passer comme s'il s'agissait d'un délégué.

+1

C'est une très bonne idée selon le principe KISS. Malheureusement, à ce stade, je ne peux pas l'utiliser :( Le problème est que la propriété que j'utilise ne fait pas partie de mon code Et l'écriture d'un wrapper ajoute des frais généraux je ne veux pas à ce stade –

2

@Dror Helper,

Je crains que vous ne pouvez pas le faire de cette façon. Le compilateur génère les méthodes get_PropertyName et set_PropertyName mais elles ne sont pas accessibles sans utiliser Reflection. IMO mieux que vous pouvez faire est de créer une fonction qui prend System.Reflection.ProperyInfo et System.Object params et renvoie propInfo.GetValue (obj, null);

1

Re: Aku réponse:

Ensuite, vous devez obtenir cette information de première propriété. Il semble que "use reflection" soit la réponse standard aux questions plus difficiles en C#, mais la réflexion donne du code pas si difficile à maintenir. Dror, pourquoi ne pas créer un délégué qui lit la propriété pour vous? C'est un simple doublure et c'est probablement la solution la plus rapide et la plus jolie à votre problème.

+0

Oui, la solution impliquera la réflexion de toute façon – aku

+1

Martijn - Je vous ai déjà répondu concernant la création d'un wrapper - même si c'est une solution assez simple, ce n'est pas ce dont j'ai besoin –

11

Vous pouvez aussi écrire quelque chose comme:

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

et exemple d'invocation:

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

Il y a aussi la possibilité d'un UnaryExpression dont vous devez rendre compte. Regardez ici: http://stackoverflow.com/a/2916344/265877 – Alex

Questions connexes