El tipo anónimo dinámico en Razor provoca RuntimeBinderException

Resuelto JarrettV asked hace 13 años • 12 respuestas

Recibo el siguiente error:

'objeto' no contiene una definición para 'RatingName'

Cuando observa el tipo dinámico anónimo, claramente tiene RatingName.

Captura de pantalla del error

Me doy cuenta de que puedo hacer esto con una tupla, pero me gustaría entender por qué aparece el mensaje de error.

JarrettV avatar Feb 26 '11 00:02 JarrettV
Aceptado

En mi opinión, los tipos anónimos que tienen propiedades internas son una mala decisión de diseño del marco .NET.

Aquí hay una extensión rápida y agradable para solucionar este problema, es decir, convirtiendo el objeto anónimo en un ExpandoObject de inmediato.

public static ExpandoObject ToExpando(this object anonymousObject)
{
    IDictionary<string, object> anonymousDictionary =  new RouteValueDictionary(anonymousObject);
    IDictionary<string, object> expando = new ExpandoObject();
    foreach (var item in anonymousDictionary)
        expando.Add(item);
    return (ExpandoObject)expando;
}

Es muy fácil de usar:

return View("ViewName", someLinq.Select(new { x=1, y=2}.ToExpando());

Por supuesto en su opinión:

@foreach (var item in Model) {
     <div>x = @item.x, y = @item.y</div>
}
DATEx2 avatar Apr 14 '2011 23:04 DATEx2

Encontré la respuesta en una pregunta relacionada . La respuesta se especifica en la publicación del blog de David Ebbo. Pasar objetos anónimos a vistas MVC y acceder a ellos usando dinámica

La razón de esto es que el tipo anónimo se pasa en el controlador de forma interna, por lo que solo se puede acceder a él desde el ensamblado en el que se declara. Dado que las vistas se compilan por separado, el enlazador dinámico se queja de que no puede superar ese límite de ensamblaje.

Pero si lo piensas bien, esta restricción de la carpeta dinámica es en realidad bastante artificial, porque si usas la reflexión privada, nada te impide acceder a esos miembros internos (sí, incluso funciona en confianza media). Por lo tanto, el enlazador dinámico predeterminado hace todo lo posible para hacer cumplir las reglas de compilación de C# (donde no se puede acceder a los miembros internos), en lugar de permitirle hacer lo que permite el tiempo de ejecución de CLR.

JarrettV avatar Feb 25 '2011 17:02 JarrettV

Usar el método ToExpando es la mejor solución.

Aquí está la versión que no requiere ensamblado System.Web:

public static ExpandoObject ToExpando(this object anonymousObject)
{
    IDictionary<string, object> expando = new ExpandoObject();
    foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(anonymousObject))
    {
        var obj = propertyDescriptor.GetValue(anonymousObject);
        expando.Add(propertyDescriptor.Name, obj);
    }

    return (ExpandoObject)expando;
}
alexey avatar Mar 29 '2013 09:03 alexey

En lugar de crear un modelo a partir de un tipo anónimo y luego intentar convertir el objeto anónimo en uno ExpandoObjectcomo este...

var model = new 
{
    Profile = profile,
    Foo = foo
};

return View(model.ToExpando());  // not a framework method (see other answers)

Puedes crear ExpandoObjectdirectamente:

dynamic model = new ExpandoObject();
model.Profile = profile;
model.Foo = foo;

return View(model);

Luego, en su vista, configura el tipo de modelo como dinámico @model dynamicy puede acceder a las propiedades directamente:

@Model.Profile.Name
@Model.Foo

Normalmente recomendaría modelos de vista fuertemente tipados para la mayoría de las vistas, pero a veces esta flexibilidad es útil.

Simon_Weaver avatar Feb 06 '2013 11:02 Simon_Weaver

Puede utilizar la interfaz improvisada del marco para incluir un tipo anónimo en una interfaz.

Simplemente devolvería un IEnumerable<IMadeUpInterface>y al final de su uso de Linq, .AllActLike<IMadeUpInterface>();esto funciona porque llama a la propiedad anónima usando el DLR con un contexto del ensamblado que declaró el tipo anónimo.

jbtule avatar Mar 02 '2011 05:03 jbtule