Attraversare un'espressione Linq per impostare il valore di un campo proprietà

c# expression-trees linq

Domanda

Questa è una domanda molto complicata anche se sembra semplice. Penso che dovrei attraversare l'intero albero delle espressioni a meno che qualcuno non conosca un modo migliore.

Diciamo che ho un oggetto utente

class User
{
    public UserAccount Account {get;set;}
}
class UserAccount
{
    public Name {get;set;}
}
var user = new User() { Account = new UserAccount()};

Come posso usare le espressioni linq per impostare la proprietà di Name

SetValue(c => c.Account.Name, "Test");

Risposta accettata

Beh, non dovresti solo attraversare l'albero delle espressioni: devi anche convertire la proprietà finale "getter" che incontri in una proprietà "setter". Essenzialmente vorrai trovare l'espressione che funge da "bersaglio" del getter (cioè l'oggetto di cui avrà la proprietà), valutarlo per ottenere il target, quindi trovare il setter corrispondente per la proprietà finale, e chiamalo con l'obiettivo e il nuovo valore.

Nota che solo richiedendo l'albero delle espressioni per rappresentare il "getter", stai perdendo parte della sicurezza in fase di compilazione che potresti aspettarti ... perché un chiamante potrebbe passare in una proprietà di sola lettura:

SetValue(c => c.Account.Name.Length, 0); // string.Length is read-only

Un'altra alternativa sarebbe quella di cambiare il tuo codice per far sì che l'espressione lambda rappresenti invece il setter:

SetValue((c, value) => c.Account.Name = value, "Test");

Quindi non avresti nemmeno bisogno di un albero di espressioni - potresti usare un semplice delegato, e basta eseguirlo in modo appropriato.

Sfortunatamente non ci hai dato abbastanza informazioni su ciò che stai cercando di ottenere per sapere se questo è un suggerimento fattibile.


Risposta popolare

Sì, dovrai attraversare l'intero albero delle espressioni che, se vuoi lavorare nel caso generale, potrebbe essere una sfida. Non puoi farlo invece:

SetValue<User>(c => c.Account.Name = "Test");

Dove SetValue è definito in questo modo:

public void SetValue<T>(Action<T> action)
{
    ...
}

O senza il parametro generico se funziona solo con l' User .



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché