¿Por qué tengo que crear manualmente expansoObject para usar correctamente la palabra clave dinámica?

StackOverflow https://stackoverflow.com/questions/14727807

  •  07-03-2022
  •  | 
  •  

Pregunta

Estaba mirando la pregunta Use 'dinámico' lanzar una excepción de runtimebinderxception. Me enfrento un problema similar:

Básicamente, quiero crear un "ayudante HTML" en ASP.NET MVC que use argumentos dinámicos, similar al parámetro HTMLARGUMENTS para muchos de los ayudantes existentes (más código a continuación):

public BootstrapCell(Action<string> emitContentAction, dynamic args)

Vista:

@using (grid.Cell(ViewContext.Writer.Write, new {Position = 4}))
{
     <p>zomg!</p>
}

Sin embargo, en el enfoque ingenuo, obtengo. RuntimeBinderException arrojado a mí, declarando que 'object' does not contain a definition for 'Position', aunque, aunque cuando se depura y flotando sobre la variable _Args, claramente lo hace tener una propiedad de posición.

La persona que llama y el callee están en ensamblajes separados. ¿Por qué sucede ese problema?

(La solución a la que se ha demostrado en la misma pregunta: Crea manualmente un expanoObject para mantener los args.)

Implementación:

public class Cell
{
    private readonly string _tagName;
    private dynamic _args;
    private Action<string> EmitContentAction;

    public BootstrapCell(Action<string> emitContentAction, dynamic args) : DisposableBaseClass
    {
        _args = args;
        EmitContentAction = emitContentAction;
        OnContextEnter();
    }

    protected void OnContextEnter()
    {
        var sb = new StringBuilder("<");
        sb.Append(_tagName);

        if (_args.Position > 0)
        {
            sb.Append(" class=\"offset");
            sb.Append(args.Position);
            sb.Append("\"");
        }

        sb.Append(">");

        EmitContentAction(sb.ToString());
    }
}

Editado para aclarar que su problema surge cuando "obviamente" se establece la propiedad de posición. Soy consciente de que si la propiedad nunca se definió en primer lugar, se debe plantear una excepción.

¿Fue útil?

Solución

Ese código es falso fatalmente.

Eso lo hace Trabaje, siempre y cuando especifique esa propiedad:

void Bar()
{
    Foo(new {Position = 0});
}

void Foo(dynamic args)
{
    Console.WriteLine(args.Position);
}

Eso saldrá 0, no tirará un RuntimeBinderException.

Pero el propósito de dicho código es la posibilidad de que la persona que llama especifique solo las propiedades necesarias y omiten el resto.
Estás tratando de comprobar esta omisión a través de if(args.Position != null). Pero eso no funciona, ya lo requiere. Position existir.

Cuando eche un vistazo a la API de enrutamiento de ASP.NET que también admite los objetos de configuración anónimos que notará que el tipo de parámetro es object y no dynamic.
Utilizando object en lugar de dynamic permitirá que su API se use a través de los límites de montaje.

¿Entonces, cómo funciona?

Al igual que en la respuesta vinculada, debe crear manualmente un diccionario de las propiedades. Si usas un viejo claro Dictionary<string, object> o un ExpandoObject Es una cuestión de preferencia.
Utilizando ExpandoObject Hará que su código sea un poco más sencillo para leer y escribir, pero no se requiere.


Sobre la excepción real que está recibiendo:
Tenga en cuenta que le dice que no puede encontrar el Position propiedad en object. Si sería un tipo anónimo que faltaba el Position Propiedad El mensaje de excepción no se referiría a object Pero a un tipo anónimo. Algo como esto:

'<>f__AnonymousType0' no contiene una definición para 'posición'

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top