Errore in C #: "un albero di espressioni non può contenere un accesso di base" - perché no?

.net c# expression-trees

Domanda

Stavo chiamando un metodo che accetta Expression<Func<bool>> .

Come parte dell'espressione che stavo passando:

this.Bottom == base.lineView.Top

Il compilatore mi ha dato un errore

un albero di espressioni non può contenere un accesso di base

Così l'ho semplicemente cambiato

this.Bottom == this.lineView.Top

perché il membro è stato comunque protetto e ora funziona.

Ma questo errore mi ha davvero colpito: perché diamine, questa base potrebbe essere un problema? Soprattutto se l'utilizzo di this funzionerà, ma sintatticamente sarà lo stesso risultato (si accede alla stessa variabile)?

Risposta accettata

Osservando la documentazione di System.Linq.Expressions.Expression , non penso ci sia un tipo di espressione che rappresenti "l'accesso ai membri di base". Non dimenticare che anche se nel tuo caso significava esattamente come this , in altri casi non lo sarebbe:

class Test
{
    void Foo()
    {
        Expression<Func<string>> baseString = () => base.ToString();
    }

    public override string ToString()
    {
        return "overridden value";
    }
}

Qui ciò rappresenterebbe una chiamata non virtuale a Object.ToString() (per this ). Non riesco a vedere come sarebbe rappresentato in un albero di espressioni, quindi l'errore.

Ora questo porta alla domanda ovvia del perché non c'è una rappresentazione di invocazione di membri di base non virtuali negli alberi di espressione - temo di non poter rispondere a quella parte ... anche se posso vedere che se si potesse costruire quell'espressione programmaticamente, che ti permetterebbe di bypassare il normale polimorfismo dall'esterno anziché solo dall'interno della classe stessa (che è il caso normale). Questa potrebbe essere la ragione. (Ammettiamo che ci sono altri modi per chiamare metodi non virtualmente, ma questa è una questione diversa, e oserei dire che ci sono situazioni in cui gli alberi di espressione sono "attendibili", ma altri non lo sono.)


Risposta popolare

La risposta di Jon è corretta. Voglio dare seguito al commento di Jon:

Posso vedere che se si potesse costruire quell'espressione a livello di codice, ciò consentirebbe di bypassare il normale polimorfismo dall'esterno anziché solo dall'interno della classe stessa (che è il caso normale). Questa potrebbe essere la ragione

Supponiamo di avere

public abstract class B // Prevent instantiation
{
    internal B() {} // Prevent subclassing outside the assembly. 
    public virtual void Dangerous() { ... } 
}
public sealed class D : B 
{ 
  public override void Dangerous() 
  { 
    if (!Allowed()) throw whatever;
    base.Dangerous();
  }

Non dovrebbe esserci modo per codice parzialmente attendibile con una D in mano per chiamare B.Dangerous di D senza eseguire il controllo di sicurezza in D.Dangerous .

Il verificatore CLR pertanto ti impedisce di eseguire un'invocazione non virtuale (un'invocazione di base è ovviamente non virtuale) su un metodo virtuale al di fuori della gerarchia di classi. In realtà, va ancora più lontano; non puoi nemmeno farlo da una classe annidata in D ! (Naturalmente se al programma viene concesso il diritto di saltare la verifica, allora puoi fare tutto ciò che vuoi, puoi trasferire i puntatori arbitrari alla memoria in codice non verificabile che è molto peggio che effettuare una chiamata statica su un metodo virtuale.)

Quando stavamo progettando alberi di espressione non volevamo affrontare questo problema di sicurezza. La cosa più semplice da fare era semplicemente rendere l'intera cosa illegale.

C'erano una serie di altri problemi di sicurezza con gli alberi di espressione che non potevano essere risolti così facilmente, ma quelli sono un argomento per un altro giorno.



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é