2009-03-19 17 views
7

Estoy buscando las mejores prácticas para crear colecciones hechas de tipos anónimos.¿Colecciones de tipos anónimos?

Hay varios enfoques - this una y la mayoría de las respuestas en this hilos asumen que toda la colección anónima se puede construir en una sola declaración.

Como los tipos anónimos se usan generalmente para reemplazar las clases que se deben usar para almacenar temporalmente (como se presenta en this SO answer), me gustaría evitar crear y usar una clase para colecciones anónimas, como this post sugiere.

En mi caso, estoy iterando sobre una colección - para cada elemento de la colección me gustaría recopilar objetos relacionados de forma anónima (actuando como una tupla). Necesito que estos tipos anónimos se incluyan en una colección y luego los ordene para seguir trabajando.

Otros enfoques que han considerado:

  1. utilizar un objeto [] o ArrayList (perder el beneficio del tipo anónimo)
  2. Creación de una clase de contenedor para los elementos requeridos (eliminando la necesidad de los anónimos tipo)

Este es el único lugar en mi código que necesito tal colección, ¿cuál sería el mejor enfoque?

Información adicional:

estoy trabajando con el legado de .NET 1.1 objetos, por lo que las colecciones que trabajo son colecciones inflexible implementar IEnumerable, y como tal, la mayoría de los métodos de extensión LINQ como .Elija ganaron' t trabajo:

ejemplo de código

foreach (Item item in myItems) 
{ 
    foreach (Confirmation confirmation in item.GetConfirmations(true)) 
    { 
     if (lastParentId != item.ParentId) 
     { 
      lastParentId = item.ParentId; 
      parentObject = new ParentItem(lastParentId); 
     } 

     itemHolder = new ArrayList { item, confirmation }; 
     if (parentObject!= null) 
     { 
      itemHolder.Add(parentObject.Rate); 
     } 

     sortConfirmations.Add(confirmation.Date, itemHolder); 
    } 
} 

// Use sortConfirmations 

Resolución

Terminé usando un diccionario genérico para juntar los elementos relacionados y usando .OrderBy() para ordenarlos - feo, pero funciona ... y es mejor que el código existente.

+0

Para obtener información; para usar LINQ con colecciones anteriores, use .Cast (), es decir, myItems.Cast () etc. –

Respuesta

6

Para una respuesta muy diferente ... LINQ?

En mi caso, soy la iteración del una colección - para cada elemento de la colección me gustaría recoger objetos relacionados en un tipo anónimo (que actúa como una tupla). Necesito estos tipos anónimos para ponerlos en una colección y luego ordenarlos para el trabajo posterior .

Eso suena como:

var list = (from item in collection 
      from related in item.Relationship 
      order by ...something... 
      select new {item,related}).ToList() 
+0

Lamentablemente necesito actualizar algunos de los objetos que recopilaré en el tipo anónimo. Estoy convirtiendo algún código existente que está poniendo estos objetos en una ArrayList y cada lista de matriz en una SorteList. Necesito lograr algo similar, pero más limpio. – Oded

+0

@Oded: a menudo, todavía es posible. Por supuesto, es difícil decirlo con seguridad sin un ejemplo concreto ... –

+0

+1 para el punto "necesitamos más información". Sospecho fuertemente que LINQ es el camino a seguir aquí. –

4

Una opción es usar un elemento ejemplo para crear la colección a través de la inferencia de tipo genérico, por ejemplo:

static List<T> CreateEmptyList<T>(T template) { 
     return new List<T>(); 
    } 
    void Foo() { 
     var list = CreateEmptyList(new { Foo = "abc" }); 
     list.Add(new { Foo = "def" }); 
     //... 
    } 

También puede hacer esto sin creación de una instancia (pero utilizando un método anónimo que nunca se obtiene la llamada), pero no creo que guarde nada realmente ... es posible que no creemos una instancia del objeto, pero sí creamos una instancia de un delegado, por lo que no es mucho ahorro ...

También mencionas ordenar los datos; ver el reply here para una forma de usar List<T>.Sort con un lambda, y por lo tanto con tipos anónimos - es decir

list.Sort(x=>x.Foo); 
20

Si usted es feliz con una matriz, se puede utilizar un inicializador de matriz:

var items = new[] { 
    new { Foo = "def" }, 
    new { Foo = "ghi" }, 
    new { Foo = "jkl" } 
}; 

A continuación, puede llamar ToList() si desea obtener una salida List<T>. La solución de Marc será ligeramente más eficiente que llamar al ToList() debido a que no necesita una copia adicional, pero creo que piensa Probablemente usaría la solución "array y ToList()" en la mayoría de los casos ya que hay menos desorden. Por supuesto, si el rendimiento es crucial para ese pedazo de código, cambia las cosas.

EDIT: Como usted está interactuando sobre una colección, sólo tiene que utilizar Select:

var anonymousItems = items.Select (item => new { Foo=item.Foo, 
               Bar=item.Other }) 
          .ToList(); 
+0

No puedo hacer eso, ya que estoy iterando sobre una colección existente para recuperar los objetos que quiero poner en el tipo anonymouse. Tenía intención de hacer collection.Add (anonType). – Oded

+0

Un pequeño consejo: las matrices son de solo lectura, por lo que si utiliza este método, considere llamar a '.ToList()' para generar una colección editable. Esto es muy útil en escenarios de prueba unitaria para cosas tales como métodos de extensión. – STW

1

LINQ es el camino a seguir. Suponiendo que desea buscar los objetos relacionados A, B y C de cada elemento en un elemento de colección y ordenar por el objeto A relacionado, iría de la siguiente manera.

var relatedObjects = items. 
     Select(item => new { A = item.A, B = item.B, C = item.C }). 
     OrderBy(item => item.A); 

Usted recibe una colección de elementos de un tipo anónimo con las tres propiedades A, B y C establecen para los objetos relacionados ordenados por el objeto relacionado A.

que no verificó eso, sino que debería ser capaz de extender la colección relacionada Objeto más tarde. Solo haga lo siguiente para agregar un solo elemento nuevo. Esto debería funcionar porque solo hay un tipo anónimo por ensamblado, creo, si los nombres y tipos de cada propiedad coinciden.

relatedObjects = relatedObjects.Union(
    Enumerable.Repeat(new { A = someA, B = someB, C = someC }, 1)) 

bastante feo debido a la Enumerable.Repeat(), pero se hace muy agradable si la unión con una colección de nuevos elementos en lugar de un único elemento nuevo.

0

éste y la mayoría de las respuestas en este hilo suponer que toda la colección anónima se puede construir en una comunicado.

Sí, normalmente crea una colección de tipo anónimo en una sola instrucción. Si necesita más declaraciones, puede terminar con una colección bastante inútil de diferentes tipos anónimos.

Los tipos anónimos son útiles cuando los creas en una sola declaración y los utilizas de inmediato. Si la creación de la colección o el procesamiento posterior es un poco más complejo, el tipo anónimo pierde parte de su utilidad.Por ejemplo, no puede pasar de forma eficiente un tipo anónimo a un método para procesar, ya que el método no conoce el tipo del objeto y, por lo tanto, tiene que usar el reflejo para sacar algo de él.

Si va a buscar repetidamente elementos en esta colección de tipos anónimos, puede crear un tipo con nombre para que pueda ponerlos en un diccionario para una búsqueda mucho más rápida.

+0

Una colección * tipada *, incluso de tipos anónimos, no sufrirá la suerte de "colección de tipos anónimos diferentes"; no puede poner un "nuevo {Foo =" acb "}" en una colección de "nuevo {Barra [int]}" –

+0

@Marc Gravell: Sí, por supuesto, necesitaría algo así como una Lista para manejar ambos tipos, perdiendo la conexión directa a la información de tipo anónimo. – Guffa

0

Me encontré con esta pregunta mientras buscaba una manera de crear una lista temporal de objetos temporales. ¿Por qué querría crear tal cosa? Estaba buscando una forma rápida de devolver JSON para obtener una lista de objetos elaborados a partir de algunos valores de otro objeto. Esto es lo que quiero decir.

Supongamos que tengo una clase de empleado en el lado del servidor que se parece a la siguiente en C#:

public class Employee 
{ 
      public int Id; 
     public int businessGroupId; 
     public string title; 
     public int positionId; 

     public string firstName; 
     public string lastName; 
     ... 
} 

Además tengo una colección de los objetos que puedo iterar fácilmente a través, algo así como lo siguiente:

List<Employee> allEmployees = new List<Employee>(); 

Ahora, yo quiero volver a mi página web llamando a la totalidad colección de Empleados, pero sólo quieren que el nombre, apellido para cada. Quiero que se devuelvan como JSON.

aquí está el punto importante

no quiero volver cada propiedad en el objeto Employee.

Sé que puedo crear fácilmente un tipo anónimo iterando a través de la colección allEmployees y construyendo un nuevo objeto cada vez.

Se vería algo como lo siguiente:

foreach (Employee e in allEmployees) 
{ 
    var tempObj = new {F_Name=e.firstName, L_Name=e.lastName}; 
} 

¿Cuál es el tipo de un tipo anónimo? :)

El truco ahora es que quiero una colección completa (Lista <>) de estos objetos anónimos. Sin embargo, no tengo manera de proporcionar a la Lista un tipo que usaré. No puedo crear un List<unknown> allTempObjects = new List<unknown>();

¿O no?

Con dinámica, es posible

que puede hacer lo siguiente y funciona muy bien:

List<dynamic> allEmployees = new List<dynamic>(); 

foreach (Employee e in allEmployees) 
{ 
      var tempObj = new {F_Name=e.firstName, L_Name=e.lastName}; 
     allEmployees.Add(tempObj); 
} 

// use the JavaScript Serializer to serialize the dynamic collection 
JavaScriptSerializer jss = new JavaScriptSerializer(); 
// write the result out to the HTTP Stream (HtmlTextWriter in overridden Render method) 

writer.Write(jss.Serialize(allEmployees)); 

verá JSON en el cliente, que tiene el siguiente aspecto:

[ 
    { 
     F_Name: "Seth", 
     L_Name: "Godin" 
    }, 
    { 
     F_Name: "Charles", 
     L_Name: "Petzold" 
    }, 
    { 
     F_Name: "Jeff", 
     L_Name: "Prosise" 
    } 
] 

Finalmente, puede preguntar por qué quiero hacer esto. La respuesta simple es que quiero un nuevo tipo que solo se usa para serializar para enviar a mi cliente. Una gran razón para un tipo anónimo y una colección anónima de tipos anónimos, ¿no crees?

Cuestiones relacionadas