vacio usa una type tipos qué parameter para palabra objetos objeto new metodos lista inicializar inicializador inicialización crear clave arreglos array anonimos c# linq .net-3.5

usa - tipos anonimos en c#



¿Cómo puedo convertir un tipo anónimo a un tipo fuerte en LINQ? (3)

Tengo una matriz de ListViewItems ( ListViewItem[] ), donde SalesOrderMaster un objeto SalesOrderMaster en cada ListViewItem.Tag para referencia posterior.

Tengo un código que ahora mismo, a través de cada ListViewItem convierte de forma segura la propiedad .Tag en un objeto SalesOrderMaster, luego agrega ese objeto a una colección de SalesOrders, solo después de verificar que la orden no existe en esa colección.

El proceso para comparar pedidos de ventas es costoso, y me gustaría convertirlo en una expresión LINQ para mayor claridad y rendimiento. (También tengo instaladas las Extensiones paralelas a .NET Framework 3.5, por lo que puedo usar eso para mejorar aún más el rendimiento de LINQ)

Así que sin más preámbulos: esto es lo que tengo, y luego lo que quiero. (Lo que quiero no se compila, así que sé que estoy haciendo algo mal, pero espero que ilustre el punto)

Lo que tengo: (lento)

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();

EDITAR: Sé que el reparto es barato, dije la "Comparación", que en este caso se traduce en la operación .Contains (orden)

EDITAR: La respuesta de todos fue increíble! Me gustarí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();


Como dijo Marc Gravell, no deberías acceder a la propiedad Tag desde diferentes hilos, y el reparto es bastante barato, por lo que tienes:

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

pero luego, desea buscar elementos distintos: aquí puede intentar usar AsParallel :

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


La parte de ese código que es costoso es llamar al método Contains en la lista. Como es una operación O (n), se vuelve más lento a medida que se agregan más objetos a la lista.

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


Veo que nadie ha abordado su necesidad de convertir un tipo anónimo a un tipo nombrado explícitamente, así que aquí va ... Al usar " select new { } " está creando un tipo anónimo, pero no es necesario. Puedes escribir tu consulta de esta manera:

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

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

Esto resuelve su problema de tipo anónimo. Sin embargo, estoy de acuerdo con Mark y Guffa en que usar una consulta paralela aquí no es su mejor opción. Para usar HashSet<SalesOrderMaster> como sugirió Guffa, puedes hacer esto:

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

(Evité usar var para que los tipos devueltos queden claros en los ejemplos).