Trabajando con C # Anonymous Types

Estoy llamando a un método que devuelve una variable de lista que contiene ac # Tipo anónimo de objetos. Por ejemplo:

List list = new List(); foreach ( Contact c in allContacts ) { list.Add( new { ContactID = c.ContactID, FullName = c.FullName }); } return list; 

¿Cómo hago referencia a las propiedades de este tipo en el código en el que estoy trabajando, como por ejemplo

 foreach ( object o in list ) { Console.WriteLine( o.ContactID ); } 

Sé que mi muestra no es posible, solo escribí de esa manera para decir que necesito identificar exactamente cada propiedad del tipo anónimo.

¡Gracias!

Solución :

No solo una de las respuestas es correcta y / o sugiere una solución de trabajo. Terminé usando la Opción 3 de la respuesta de Greg. ¡Y aprendí algo muy interesante sobre la dynamic en .NET 4.0!

No puede devolver una lista de tipo anónimo, tendrá que ser una lista de object . Por lo tanto, perderá la información del tipo.

Opción 1
No use un tipo anónimo. Si intenta utilizar un tipo anónimo en más de un método, cree una clase real.

opcion 2
No downcast su tipo anónimo a object . (debe estar en un método)

 var list = allContacts .Select(c => new { c.ContactID, c.FullName }) .ToList(); foreach (var o in list) { Console.WriteLine(o.ContactID); } 

Opción 3
Use la palabra clave dinámica (Se requiere .NET 4)

 foreach (dynamic o in list) { Console.WriteLine(o.ContactID); } 

Opción 4
Usa un reflection sucio

 foreach ( var o in list ) { Console.WriteLine( o.ContactID ); } 

esto solo funcionará si la lista es IEnumerable , como esta:

 var list = allContacts.Select(c => new { ContactID = c.ContactID, FullName = c.FullName }); } 

pero no puede devolver tipos anónimos, porque debe definir el tipo de devolución (no puede devolver var ) y los tipos anónimos no pueden tener nombres. deberías crear un tipo no anónimo si deseas pasarlo. En realidad, los tipos anónimos no deben usarse demasiado, excepto en el interior de las consultas.

Si tienes un método como este:

  List GetContactInfo() { List list = new List(); foreach ( Contact c in allContacts ) { list.Add( new { ContactID = c.ContactID, FullName = c.FullName }); } return list; } 

En realidad, no deberías hacer esto, pero hay una técnica muy fea y no a prueba de futuro que puedes usar:

  static T CastByExample(object target, T example) { return (T)target; } // ..... var example = new { ContactID = 0, FullName = "" }; foreach (var o in GetContactInfo()) { var c = CastByExample(o, example); Console.WriteLine(c.ContactID); } 

Se basa en el hecho (¡que puede cambiar!) De que el comstackdor reutiliza tipos anónimos para tipos que tienen la misma “forma” (nombres y tipos de propiedades). Como su “ejemplo” coincide con la “forma” del tipo en el método, se reutiliza el mismo tipo.

Sin embargo, las variables dinámicas en C # 4 son la mejor manera de resolver esto.

No puedes hacer esto con tipos anónimos. Simplemente crea una clase / estructura de contacto y úsala.

 List list = new List(); foreach ( Contact c in allContacts ) { list.Add( c ); } 

Entonces puedes hacer esto:

 foreach ( var o in list ) { Console.WriteLine( o.ContactID ); } 

…o esto:

 foreach ( object o in list ) { Console.WriteLine( ((Contact)o).ContactID ); //Gives intellisense } 

Por supuesto, en ese caso debería crear una lista de contactos en lugar de una lista de objetos:

 List list = new List(); foreach ( Contact c in allContacts ) { list.Add( c ); } 

EDITAR: se perdió la parte esencial de la pregunta. Ahora arreglado.
EDITAR: Cambió la respuesta una vez más. Véase más arriba.

reemplazar objeto con var en cada construcción puede funcionar

Sé que llego tarde a la fiesta pero investigo algo más y encontré este artículo que responde a su pregunta.

Es posible convertir la lista de objetos en el tipo anónimo.

  public static void Main() { foreach (object item in GetList()) { var x = Cast(item, new { ContactID = 0, FullName = "" }); Console.WriteLine(x.ContactID + " " + x.FullName); } } public static IEnumerable GetList() { yield return new { ContactID = 4, FullName = "Jack Smith" }; yield return new { ContactID = 5, FullName = "John Doe" }; } public static T Cast(object obj, T type) { return (T)obj; } 

lista de vuelta

 public static void Main() { foreach (object item in GetList()) { var x = Cast(item, new { ContactID = 0, FullName = "" }); Console.WriteLine(x.ContactID + " " + x.FullName); } } public static IEnumerable GetList() { yield return new { ContactID = 4, FullName = "Jack Smith" }; yield return new { ContactID = 5, FullName = "John Doe" }; } public static T Cast(object obj, T type) { return (T)obj; } 

yo usaría

 allContacts .Select(c => new { c.ContactID, c.FullName }) .ToList() .ForEach(c => { ...do stuff; }); 

entonces no necesitas declarar nada. creo que menos statement, menos punto y coma conduce a menos errores