create - lambda c#
Error en C#: "un árbol de expresiones puede no contener un acceso base", ¿por qué no? (2)
Estaba llamando a un método que acepta Expression<Func<bool>>
.
Como parte de la expresión que estaba pasando:
this.Bottom == base.lineView.Top
El compilador me dio un error que
un árbol de expresiones puede no contener un acceso base
Así que simplemente lo cambié a
this.Bottom == this.lineView.Top
porque el miembro estaba protegido de todos modos y ahora funciona.
Pero este error realmente me atrapó: ¿por qué demonios sería esta base
un problema? Especialmente si usar this
cambio funcionará pero sintácticamente será el mismo resultado (se accede a la misma variable)?
La respuesta de Jon es correcta. Quiero seguir el comentario de Jon:
Puedo ver que si pudieras construir esa expresión programáticamente, eso te permitiría eludir el polimorfismo normal desde el exterior en lugar de solo desde dentro de la clase (que es el caso normal). Esa puede ser la razón
Supongamos que tiene
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();
}
No debería haber forma de que el código sea parcialmente confiable con una D
en la mano para llamar a B.Dangerous
en la instancia de D
sin realizar la verificación de seguridad en D.Dangerous
.
Por lo tanto, el verificador de CLR le impide realizar una invocación no virtual (una invocación de base es, por supuesto, no virtual) en un método virtual desde fuera de la jerarquía de clases. De hecho, va aún más lejos; ¡ni siquiera puedes realizar eso desde una clase anidada dentro de D
! (Por supuesto, si se le concede a su programa el derecho de omitir la verificación, puede hacer lo que desee; puede desviar punteros arbitrarios a la memoria en un código no verificable que es mucho peor que realizar una llamada estática en un método virtual).
Cuando estábamos diseñando árboles de expresión, no queríamos lidiar con este desordenado problema de seguridad. Lo más fácil era simplemente hacer que todo fuera ilegal.
Hubo una serie de otros problemas de seguridad con los árboles de expresión que no podrían resolverse tan fácilmente, pero esos son un tema para otro día.
Mirando la documentación de System.Linq.Expressions.Expression
, no creo que haya un tipo de expresión que represente "acceso de miembro base". No olvide que aunque en su caso significó lo mismo que this
, en otros casos no:
class Test
{
void Foo()
{
Expression<Func<string>> baseString = () => base.ToString();
}
public override string ToString()
{
return "overridden value";
}
}
Aquí eso representaría una llamada no virtual a Object.ToString()
(para this
). No puedo ver cómo se representaría eso en un árbol de expresiones, de ahí el error.
Ahora eso nos lleva a la pregunta obvia de por qué no hay una representación de la invocación de miembros de base no virtuales en los árboles de expresiones. Me temo que no puedo responder esa parte ... aunque puedo ver que si puedes construir esa expresión programáticamente, que le permitiría eludir el polimorfismo normal desde el exterior en lugar de desde dentro de la clase (que es el caso normal). Esa puede ser la razón. (Es cierto que hay otras maneras de llamar a los métodos de forma no virtual, pero esa es una cuestión diferente, y me atrevo a decir que hay situaciones en las que los árboles de expresiones son "confiables" pero otros no).