Func <> weisen Sie dem Ergebnis einen Wert zu

c# expression-trees lambda

Frage

Was ich versuche, scheint einfach zu sein, aber ich kann keinen Weg finden. Nehmen wir an, ich habe eine Methode mit dieser Signatur:

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

Was ich in meiner Methode tun möchte, ist: das Func auf Item anwenden, die Eigenschaft des Typs K abrufen, auf die der Binding-Ausdruck zeigt, und ihm "value" zuweisen.

Wenn der Bindungsausdruck etwas wie folgt lautet:

c => c.Property

Wenn "c" "T" ist und "Eigenschaft" "K" ist, kann ich leicht eine Reflexion verwenden und den Wert mithilfe von FieldInfo festlegen. Der folgende Code funktioniert:

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

Aber der Ausdruck könnte so etwas sein:

c => c.SubClass.Property

oder

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

In diesem Fall funktioniert der Reflection-Code nicht, da "Property" nicht direkt zu T gehört, aber immer noch ein gültiger Lambda-Ausdruck für die Signatur der Methode ist.

Ich weiß, dass, wenn ich den Func kompiliere und es auf meinem Element des Typs TI führe, die Eigenschaft bekomme, aber es ist wie eine "Kopie" davon und keine Referenz davon, also selbst wenn ich ihm den Wert zugebe, die Eigenschaft auf dem ursprünglichen Artikel wird nicht geändert.

Wenn jemand eine saubere Lösung dafür hat oder mich auf etwas aufmerksam macht, das mir bessere Kenntnisse von Expression Trees ermöglicht, sind Sie herzlich willkommen.

Akzeptierte Antwort

Es hört sich so an, als würdest du nicht wirklich ein "K" von einem T wollen, sondern stattdessen ein K einem K zuweisen, von dem T weiß, oder?

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

Scheint korrekter zu sein, weil die Bindung ein Delegierter ist, der ein T nehmen kann und T sagt, dass er mit einem K das Richtige tun soll, richtig? Nennen Sie es so?

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

Beliebte Antwort

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

Verwendung:

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


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum