2011-01-14 6 views
2

Ce que j'essaie de faire semble simple, mais je ne trouve pas de solution. Supposons que j'ai une méthode avec cette signature:Func <> affecter une valeur au résultat

public void Foo<T,K>(Expression<Func<T,K>> binding, T item, K value) 

Ce que je veux faire dans ma méthode: application du Func au point, obtenir la propriété de type K à laquelle les points d'expression de liaison, et attribuer " valeur "pour cela.

Si l'expression de liaison est quelque chose comme:

c => c.Property 

Où « c » est « T » et « la propriété » est « K », je peux utiliser une réflexion facilement et définir la valeur à l'aide FieldInfo. Le code suivant fonctionne:

(((binding as LambdaExpression).Body as MemberExpression).Member as FieldInfo).SetValue(item, value); 

Mais l'expression pourrait être quelque chose comme ceci:

c => c.SubClass.Property 

ou

c => c.SubClass1.SubClass2.SubClassN.Property 

Dans ce cas, le code de réflexion ne fonctionne pas, comme « la propriété "n'appartient pas directement à T, mais c'est toujours une expression lambda valide pour la signature de la méthode.

Je sais que si je compile le Func et l'exécute sur mon élément de type TI, j'obtiens la propriété, mais c'est comme une "copie" de celui-ci, et non une référence, donc même si j'affecte la valeur à Dans ce cas, la propriété de l'élément d'origine ne change pas.

Si quelqu'un a une solution propre à cela, ou si vous me signalez quelque chose qui peut me permettre une meilleure connaissance des arbres d'expression, vous êtes le bienvenu.

+1

Votre 'copie' hypothèse est valable que s'il y a un 'struct' quelque part dans cette 'chaîne'. Pour les types de référence, l'affectation sera bonne. – leppie

+0

Je m'attendais à beaucoup, mais je l'ai essayé et ne fonctionne pas. "SubClass" sont tous des "classes" donc types de référence, ainsi que T. Même la propriété finale dans ce que j'essayais de faire était une classe, donc un type de référence. –

Répondre

3

On dirait que vous ne voulez pas vraiment un 'K' d'un T, mais à la place vous voulez assigner un K à un K que T connaît, non?

public void Foo<T,K>(Action<T,K> binding, T item, K value) 
{ 
    binding(item, value); 
} 

semble plus correcte, car la liaison est un délégué qui peut prendre T et T dire de faire la bonne chose avec un K, non? Appelez ça comme ça?

Foo<T,K>((t, k) => t.SubClass.Property = k, aT, aK); 
+1

C'est EXACTEMENT ce dont j'avais besoin, et c'était en effet trivial, mais dans la ruée du travail de bureau, je ne pouvais pas y penser. Et j'ai utilisé Action <> plusieurs fois par le passé. Que je suis bête. Merci beaucoup, vous avez sauvé ma journée. –

1
static void AssignValue<TSource, TResult>(Expression<Func<TSource, TResult>> expression, TSource source, TResult result) 
{ 
    var paramExp = expression.Parameters.Single(); 
    var assignExp = Expression.Assign(expression.Body, Expression.Constant(result)); 
    var lambdaExp = Expression.Lambda(assignExp, paramExp); 
    lambdaExp.Compile().DynamicInvoke(source); 
} 

Utilisation:

class Product 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
} 

var product = new Product { ID = 99, Name = "haha" }; 
AssignValue<Product, string>(p => p.Name, product, "changed"); 
+0

Ce n'est pas ce que j'essaie de faire. Votre méthode "lit" la valeur de la propriété. Je veux "écrire" la propriété elle-même. Peut-être que je ne l'ai pas bien expliqué, je ferai quelques corrections plus tard. –

+0

@ Matteo Mosca: Je sais ce que vous voulez maintenant. Donnez-moi le temps de modifier la réponse. –

+0

@ Matteo Mosca: Voir mon édition. –

Questions connexes