¿Cómo acceder a la propiedad de tipo anónimo en C #?

Tengo esto:

List nodes = new List(); nodes.Add( new { Checked = false, depth = 1, id = "div_" + d.Id }); 

… y me pregunto si puedo agarrar la propiedad “Verificada” del objeto anónimo. No estoy seguro de si esto es posible. Intenté hacer esto:

if (nodes.Any(n => n["Checked"] == false)) … pero no funciona.

Gracias

Si desea una lista de tipos anónimos fuertemente tipada, también deberá hacer que la lista sea de tipo anónimo. La forma más fácil de hacer esto es proyectar una secuencia como una matriz en una lista, por ejemplo,

 var nodes = (new[] { new { Checked = false, /* etc */ } }).ToList(); 

Entonces podrás acceder a él como:

 nodes.Any(n => n.Checked); 

Debido a la forma en que funciona el comstackdor, lo siguiente también debería funcionar una vez que haya creado la lista, porque los tipos anónimos tienen la misma estructura, por lo que también son del mismo tipo. No tengo un comstackdor a mano para verificar esto sin embargo.

 nodes.Add(new { Checked = false, /* etc */ }); 

Si está almacenando el objeto como object tipo, necesita usar la reflexión. Esto es cierto para cualquier tipo de objeto, anónimo o de otro tipo. En un objeto o, puede obtener su tipo:

 Type t = o.GetType(); 

Entonces a partir de eso buscas una propiedad:

 PropertyInfo p = t.GetProperty("Foo"); 

Entonces de eso puedes obtener un valor:

 object v = p.GetValue(o, null); 

Esta respuesta está atrasada desde hace mucho tiempo para una actualización de C # 4:

 dynamic d = o; object v = d.Foo; 

Y ahora otra alternativa en C # 6:

 object v = o?.GetType().GetProperty("Foo")?.GetValue(o, null); 

Tenga en cuenta que utilizando ?. ¡Hacemos que la v resultante sea null en tres situaciones diferentes!

  1. o es null , por lo que no hay ningún objeto en absoluto
  2. o no es null pero no tiene una propiedad Foo
  3. o tiene una propiedad Foo pero su valor real pasa a ser null .

Por lo tanto, esto no es equivalente a los ejemplos anteriores, pero puede tener sentido si desea tratar los tres casos de la misma manera.

Podrías recorrer las propiedades del tipo anónimo usando Reflection; ver si hay una propiedad “Checked” y si hay, entonces obtener su valor.

Consulte esta publicación del blog: http://blogs.msdn.com/wriju/archive/2007/10/26/c-3-0-anonymous-type-and-net-reflection-hand-in-hand.aspx

Así que algo como:

 foreach(object o in nodes) { Type t = o.GetType(); PropertyInfo[] pi = t.GetProperties(); foreach (PropertyInfo p in pi) { if (p.Name=="Checked" && !(bool)p.GetValue(o)) Console.WriteLine("awesome!"); } } 

La respuesta aceptada describe correctamente cómo se debe declarar la lista y es muy recomendable para la mayoría de los escenarios.

Pero me encontré con un escenario diferente, que también cubre la pregunta formulada. ¿Qué ViewData["htmlAttributes"] si tiene que usar una lista de objetos existente, como ViewData["htmlAttributes"] en MVC? ¿Cómo puede acceder a sus propiedades (generalmente se crean a través del new { @style="width: 100px", ... } )?

Para este escenario ligeramente diferente, quiero compartir con ustedes lo que descubrí. En las soluciones a continuación, asumo la siguiente statement para los nodes :

 List nodes = new List(); nodes.Add( new { Checked = false, depth = 1, id = "div_1" }); 

1. Solución con dinámica.

En C # 4.0 y versiones superiores, simplemente puede convertir a dynamic y escribir:

 if (nodes.Any(n => ((dynamic)n).Checked == false)) Console.WriteLine("found not checked element!"); 

Nota: Esto está usando un enlace tardío, lo que significa que se reconocerá solo en tiempo de ejecución si el objeto no tiene una propiedad Checked y arroja una RuntimeBinderException en este caso, por lo que si intenta usar una propiedad Checked2 no existente, obtendrá la siguiente mensaje en tiempo de ejecución: "'<>f__AnonymousType0' does not contain a definition for 'Checked2'" .

2. Solución con reflexión.

Fondo

Como punto de partida, encontré una buena respuesta aquí . La idea es convertir el tipo de datos anónimos en un diccionario utilizando la reflexión.

Inspirado por el código en el enlace anterior, creé una clase de extensión, que simplifica el acceso a propiedades anónimas. Con esta clase simplemente puede hacer la consulta de la siguiente manera:

 if (nodes.AccessListItems().Any(n => (bool)n["Checked"] == false)) { Console.WriteLine("found not checked element!"); } 

Todo lo que se requiere es que agregue la clase de extensión a continuación:

 // simplifies access to anonymous properties public static class AnonymousTypeExtensions { // make properties of object accessible // eg. x.AccessProperties() or x.AccessProperties()["PropName"] public static IDictionary AccessProperties(this object o, string propertyName=null) { Type type = o?.GetType(); var properties = type?.GetProperties() ?.Select(n => n.Name) ?.ToDictionary(k => k, k => type.GetProperty(k).GetValue(o, null)); return properties; } // returns specific property, iexAccessProperty(propertyName) public static object AccessProperty(this object o, string propertyName) { return o?.AccessProperties()?[propertyName]; } // converts object list into list of properties public static List AccessListItems(this List objectList) { var accessibleList = new List(); foreach (object obj in objectList) { accessibleList.Add(obj.AccessProperties()); } return accessibleList; } } 

El código anterior está utilizando los operadores condicionales nulos , disponibles desde C # versión 6.0 – si está trabajando con comstackdores más antiguos, simplemente reemplace ?. por y ?[ por [ . De lo contrario, manténgalo tal como está, porque facilita mucho el manejo nulo.

Nota: Al igual que la otra solución con dinámica, esta solución también utiliza un enlace tardío, pero en este caso no está obteniendo una excepción, simplemente no encontrará el elemento si se refiere a una propiedad que no existe. Lo que podría ser útil para algunas aplicaciones es que se hace referencia a la propiedad a través de una cadena.