¿Es posible declarar un tipo anónimo en C # con un conjunto variable / dinámico de campos?

anonymous-types c# dapper dynamic

Pregunta

En C #, me gustaría averiguar si es posible declarar un tipo anónimo donde los campos no se conocen hasta el tiempo de ejecución.

Por ejemplo, si tengo una Lista de pares clave / valor, ¿puedo declarar un tipo anónimo según el contenido de esa lista? El caso específico con el que estoy trabajando es pasar los parámetros a Dapper, donde no sé de antemano cuántos parámetros tendré.

List<Tuple<string, string>> paramList = new List<Tuple<string, string>>() {
    new Tuple<string, string>("key1", "value1"),
    new Tuple<string, string>("key2", "value2")
    ...
};

Me gustaría convertir esta lista (o un mapa equivalente) en un tipo anónimo que puedo pasar a Dapper como parámetros de consulta. Entonces, idealmente, la lista anterior terminaría luciendo así, si se define como un tipo anónimo:

new { key1=value1, key2=value2, ... }

He visto varias preguntas sobre StackOverflow preguntando por la extensión de tipos anónimos después de su declaración ("objetos externos") o declarando campos arbitrarios en un objeto después de su creación, pero no necesito hacerlo ... solo necesito declarar los tipos dinámicamente por adelantado una vez. Mi sospecha es que requerirá una reflexión elegante, si es posible en absoluto.

Según entiendo, el compilador define un tipo para las clases anónimas bajo el capó en tiempo de compilación, por lo que si los campos de esa clase no están disponibles hasta el tiempo de ejecución, es posible que no tenga suerte. Mi caso de uso puede de hecho no ser diferente en realidad que usar un "objeto extendo" para definir campos arbitrarios, en cualquier momento.

Alternativamente, si alguien sabe de una mejor manera de pasar los parámetros de consulta a Dapper (en lugar de declarar una clase anónima), me encantaría saber acerca de eso también.

¡Gracias!

ACTUALIZAR

¡Perdón por el retraso en volver a este! Estas respuestas fueron geniales, ojalá pudiera darles puntos a todos. Terminé usando la solución de jbtule (con edición de Sam Saffron), pasando IDynamicParameters a Dapper, así que sentí que tenía que darle la respuesta. Las otras respuestas también fueron buenas y respondieron preguntas específicas que yo había formulado. ¡Realmente aprecio el tiempo de todos en esto!

Respuesta aceptada

Los creadores de Dapper eran muy conscientes de este problema. Este tipo de funcionalidad es realmente necesaria para los ayudantes INSERT y UPDATE .

Los métodos Query , Execute y QueryMultiple toman un parámetro dynamic . Esto puede ser un tipo anónimo, un tipo concreto o un objeto que implementa IDynamicParameters .

public interface IDynamicParameters
{
    void AddParameters(IDbCommand command, Identity identity);
}

Esta interfaz es muy útil, se llama AddParameters justo antes de ejecutar cualquier SQL. Esto no solo le brinda un control rico sobre los parámetros enviados a SQL. Le permite conectar los DbParameters específicos de DB, ya que tiene acceso al comando (puede convertirlo al db específico). Esto permite el soporte de parámetros de valores de tabla, etc.

Dapper contiene una implementación de esta interfaz que se puede usar para sus propósitos llamada DynamicParameters . Esto le permite tanto paquetes de parámetros anónimos concatenados como agregar valores específicos.

Puede usar el método AddDynamicParams para agregar un tipo anónimo.

var p = new DynamicParameters();
p.AddDynamicParams(new{a = "1"});
p.AddDynamicParams(new{b = "2", c = "3"});
p.Add("d", "4")
var r = cnn.Query("select @a a, @b b, @c c, @d d", p);
// r.a == 1, r.b == 2, r.c == 3, r.d == 4

Respuesta popular

En C #, me gustaría averiguar si es posible declarar un tipo anónimo donde los campos no se conocen hasta el tiempo de ejecución.

Los tipos anónimos son generados por el compilador. Desea saber si el compilador generará un tipo generado por el compilador con tipos de campo desconocidos para el compilador . Claramente no puede hacerlo; como conjeturas correctamente, no tienes suerte.

He visto varias preguntas sobre StackOverflow preguntando sobre la extensión de tipos anónimos después de que se declaran ("objetos extendo")

Generalmente llamamos a esos objetos "expando".

Si lo que quiere hacer es crear un objeto expandido basado en un diccionario de pares clave-valor, entonces use la clase ExpandoObject para hacer eso. Vea este artículo de MSDN para más detalles:

http://msdn.microsoft.com/en-us/magazine/ff796227.aspx

Si lo que quieres hacer es generar una clase .NET bona fide en tiempo de ejecución, puedes hacerlo también. Como notas correctamente, necesitas un reflejo elegante para hacerlo. Lo que quiere hacer es crear un conjunto coleccionable (así llamado porque a diferencia de un ensamblaje normal, lo genera en tiempo de ejecución y el recolector de basura lo limpiará cuando haya terminado con él).

Consulte http://msdn.microsoft.com/en-us/library/dd554932.aspx para obtener detalles sobre cómo crear un conjunto coleccionable y emitir un tipo con un TypeBuilder.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué