2009-04-29 11 views
17

Tengo una matriz de ListViewItems (ListViewItem[]), donde almaceno un objeto SalesOrderMaster en cada ListViewItem.Tag para referencia futura.¿Cómo puedo convertir el tipo anónimo a tipo fuerte en LINQ?

Tengo un código que en este momento, cada ListViewItem arroja con seguridad la propiedad .Tag en un objeto SalesOrderMaster, luego agrega ese objeto a una colección de SalesOrders, solo después de verificar para asegurarse de que el pedido no exista ya en esa colección.

El proceso para comparar pedidos de venta es costoso, y me gustaría convertir esto a una expresión LINQ para mayor claridad y rendimiento. (También tengo el Parallel Extensions to .NET Framework 3.5 instalado, así que puedo usar eso para mejorar aún más el rendimiento de LINQ)

Sin más preámbulos: Esto es lo que tengo, y luego lo que quiero. (Lo que yo quiero no se compilará, así que sé que estoy haciendo algo mal, pero espero que ilustra este punto)

Lo que tengo: (Slow)

foreach (ListViewItem item in e.Argument as ListViewItem[]) 
      { 
       SalesOrderMaster order = item.Tag as SalesOrderMaster; 
       if (order == null) 
       { 
        return; 
       } 
       if (!All_SalesOrders.Contains(order)) 
       { 
        All_SalesOrders.Add(order); 
       } 
      } 

Lo que quiero: (Teoría)

List<SalesOrderMaster> orders = 
(from item in (e.Argument as ListViewItem[]).AsParallel() 
select new { ((SalesOrderMaster)item.Tag) }).Distinct(); 

EDIT: sé que el reparto es barato, me dijo que el "comparar", que en este caso se traduce en los .Contains (orden) la operación

EDIT: la respuesta de todo el mundo era increíble! Desearía poder marcar más de una respuesta, pero al final tengo que elegir una.

EDIT: Esto es lo que terminó con:

List<SalesOrderMaster> orders = 
(from item in (e.Argument as ListViewItem[]) select (SalesOrderMaster) item.Tag).GroupBy(item => item.Number).Select(x => x.First()).ToList(); 

Respuesta

17

veo que nadie ha abordado su necesidad de convertir un tipo anónimo a un tipo con nombre de forma explícita, así que aquí va ... mediante el uso de "select new { }" va a crear un tipo anónimo, pero no es necesario Usted puede escribir su consulta como esta:

List<SalesOrderMaster> orders = 
    (from item in (e.Argument as ListViewItem[]).AsParallel() 
    select (SalesOrderMaster)item.Tag) 
    .Distinct() 
    .ToList(); 

en cuenta que la consulta selecciona (SalesOrderMaster)item.Tag sin new { }, por lo que no crea un tipo anónimo. También tenga en cuenta que agregué ToList() ya que quiere un List<SalesOrderMaster>.

Esto soluciona el problema de tipo anónimo.Sin embargo, estoy de acuerdo con Mark y Guffa en que usar una consulta paralela aquí no es tu mejor opción. Para utilizar HashSet<SalesOrderMaster> como se sugiere Guffa, usted puede hacer esto:

IEnumerable<SalesOrderMaster> query = 
    from item in (ListViewItem[])e.Argument 
    select (SalesOrderMaster)item.Tag; 

HashSet<SalesOrderMaster> orders = new HashSet<SalesOrderMaster>(query); 

(I evitado el uso de var por lo que los tipos devueltos son claras en los ejemplos.)

+1

+1 para obtener información sobre 'new {}' –

+0

@ [Lucas] Pero, ¿cómo podemos seleccionar varios campos usando este método? ¿Hay alguna alternativa al uso de un tipo anónimo? – Zesty

+1

Ah, no importa, lo tengo. seleccione nueva Persona (e.First_name, e.Last_name)). ToList () – Zesty

3

La parte en la que el código que es caro está llamando al método Contains en la lista. Como es una operación O (n), se vuelve más lenta cuanto más objetos se agregan a la lista.

Solo use HashSet<SalesOrderMaster> para los objetos en lugar de List<SalesOrderMaster>. El método Contains de HashSet es una operación O (1), por lo que su ciclo será una operación O (n) en lugar de una operación O (n * n).

+1

Pero la adición de elementos a un conjunto de hash es un O (n) operación cada O (log n) agrega, por lo que obtienes O (n * log n) – configurator

+0

Sí, añadir elementos a un conjunto de hash es a veces una operación O (n), pero también agrega elementos a una lista, por lo que el resultado es casi lo mismo. – Guffa

+0

Para que quede claro, agregar el elemento lleva aproximadamente el mismo tiempo para ambos, es determinar si ya contiene el elemento que es mucho más rápido en HashSet. ¿Es asi? – Lucas

3

como Marc Gravell dijo, no debe acceder a la propiedad Tag de diferentes hilos, y el elenco es bastante barato, por lo que tiene:

var items = (e.Argument as ListViewItem[]).Select(x=>x.Tag) 
     .OfType<SalesOrderMaster>().ToList(); 

pero entonces, que desea encontrar elementos distintos - aquí puede probar a usar AsParallel:

var orders = items.AsParallel().Distinct(); 
Cuestiones relacionadas