¿Cómo usar Expression para construir un tipo anónimo?

anonymous-types c# expression-trees linq

Pregunta

En C # 3.0 puede usar Expression para crear una clase con la siguiente sintaxis:

var exp = Expression.New(typeof(MyClass));
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();

¿Pero cómo usas Expression para crear una clase anónima?

//anonymousType = typeof(new{ Name="abc", Num=123});
Type anonymousType = Expression.NewAnonymousType???  <--How to do ?
var exp = Expression.New(anonymousType);
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();

Respuesta aceptada

Está cerca, pero debe tener en cuenta que los tipos anónimos no tienen constructores predeterminados. El siguiente código imprime { Name = def, Num = 456 } :

Type anonType = new { Name = "abc", Num = 123 }.GetType();
var exp = Expression.New(
            anonType.GetConstructor(new[] { typeof(string), typeof(int) }),
            Expression.Constant("def"),
            Expression.Constant(456));
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();
Console.WriteLine(myObj);

Si no tiene que crear muchas instancias de este tipo, Activator.CreateInstance igual de bien (es más rápido para algunas instancias, pero más lento para muchas). Este código imprime { Name = ghi, Num = 789 } :

Type anonType = new { Name = "abc", Num = 123 }.GetType();
object myObj = Activator.CreateInstance(anonType, "ghi", 789);
Console.WriteLine(myObj);

Respuesta popular

Como un tipo anónimo no tiene un constructor vacío predeterminado, no puede usar la sobrecarga Expression.New(Type) ... tiene que proporcionar el ConstructorInfo y los parámetros al método Expression.New . Para hacerlo, debe poder obtener el Tipo ... por lo que necesita crear una instancia "stub" del tipo anónimo, y usarla para obtener el Type , y el ConstructorInfo , y luego pasar los parámetros a la Expression.New método.

Me gusta esto:

var exp = Expression.New(new { Name = "", Num = 0 }.GetType().GetConstructors()[0], 
                         Expression.Constant("abc", typeof(string)), 
                         Expression.Constant(123, typeof(int)));
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow