Casting de tipo anónimo a dynamic.

Tengo una función que devuelve un tipo anónimo que quiero probar en mi controlador MVC.

public JsonResult Foo() { var data = new { details = "something", more = "More" }; return Json(data); } 

Quiero verificar los datos que obtengo de la función Foo. Lo que estoy haciendo ahora es obtener el tipo de datos y obtener sus valores de propiedades con una reflexión.

 [Test] public void TestOne() { var data = _controller.Foo().Data; var details = data.GetType().GetProperty("details").GetValue(data, null); var more = data.GetType().GetProperty("more").GetValue(data, null); Assert.AreEquals("something", details); Assert.AreEquals("More", more); } 

¿Hay una forma simple similar a esto para verificar las propiedades anónimas?

 [Test] public void TestTwo() { var data = (dynamic) _controller.Foo().Data; var details = data.details; // RunTimeBinderException object does not contain definition for details var more = data.more; Assert.AreEquals("something", details); Assert.AreEquals("More", more); } 

Los objetos anónimos son internal , lo que significa que sus miembros están muy restringidos fuera de la asamblea que los declara. dynamic accesibilidad dynamic respeta, por lo que pretende no poder ver a esos miembros. Si el sitio de llamada estaba en el mismo ensamblaje, espero que funcione.

Su código de reflexión respeta la accesibilidad del miembro , pero pasa por alto la accesibilidad del tipo, por lo tanto, funciona.

En resumen: no.

Este blog tuvo una respuesta de trabajo: http://blog.jorgef.net/2011/06/converting-any-object-to-dynamic.html – Gracias @ Jorge-Fioranelli.

 public static class DynamicExtensions { public static dynamic ToDynamic(this object value) { IDictionary expando = new ExpandoObject(); foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType())) expando.Add(property.Name, property.GetValue(value)); return expando as ExpandoObject; } } 

El tipo anónimo es un tipo estático regular en .NET, es solo que no le das un nombre (un comstackdor, sin embargo, sí lo hace). Es por eso que convertirlo en dynamic no funcionará. Sin embargo, si tiene control sobre Foo() , puede construir y devolver un objeto dynamic lugar de anónimo, y luego su código funcionará. Esto debería funcionar:

 dynamic JsonResult Foo() { dynamic data = new ExpandoObject(); data.details = "something"; data.mode = "More"; return Json(data); } 

Según lo sugerido por @TrueWill y @Marc Gravell, quienes también se refirieron a esta publicación del blog

Ya que esto es para pruebas de unidad, puede usar InternalsVisibleTo. Ver tipos anónimos son internos, C # 4.0 Dynamic Beware! Gracias a @MarcGravell por señalar que los objetos anónimos son internos.

Línea inferior: configure una asignación [assembly: InternalsVisibleTo("foo")] si desea compartir un objeto anónimo de un ensamblaje a otro. En el caso de OP, sería cuestión de configurar esto en el proyecto del controlador MVC, refiriéndose al proyecto de prueba . En mi caso específico, al revés (ya que estoy pasando un objeto anónimo de mi proyecto de prueba al proyecto de “código de producción”).

La forma más fácil en ese “otro proyecto” para poder usarlo es definitivamente convertirlo en dynamic y luego usar las propiedades como de costumbre. Funciona, no hay problemas de ningún tipo.

Entonces, conclusión: siento que la respuesta de Marc Gravell es ligeramente incorrecta; esto se puede hacer claramente
(Si los proyectos en cuestión son modificables por usted, puede configurar el mapeo InternalsVisibleTo en consecuencia, y esto no representa un problema por ninguna otra razón).

Puede usar NewtonSoft o las bibliotecas de Asp.net MVC:

var data = Json.Decode(Json.Encode(_controller.Foo().Data));

var data=JsonConvert.DeserializeObject>(JsonConvert.SerializeObject((_controller.Foo().Data))