2008-12-16 25 views
7

A menudo encuentro que linq es problemático cuando se trabaja con objetos de colección personalizados. Ellos son a menudo defened comoLinq con colección base personalizada

La colección base

abstract class BaseCollection<T> : List<T> { ... } 

las colecciones se define como

class PruductCollection : BaseCollection<Product> { ... } 

¿Hay una mejor manera de agregar los resultados de un expession LINQ a esta colección de AddRange o concat?

var products = from p in HugeProductCollection 
       where p.Vendor = currentVendor 
       select p; 
PruductCollection objVendorProducts = new PruductCollection(); 
objVendorProducts.AddRange(products); 

Sería bueno si el objeto devuelto de la consulta linq fuera de mi tipo de colección personalizada. Como parece necesitar enumerar la colección dos veces para hacer esto.

EDIT: Después de leer las respuestas, creo que la mejor solución es implementar una extensión ToProduct(). Me pregunto si la covarianza/contravarianza en C# 4.0 ayudará a resolver este tipo de problemas.

+1

"Como parece que necesita para enumerar la colección dos veces para hacer esto" - Dado que la mayoría de las consultas de linq se evalúan de forma diferida, la colección solo se enumerará una vez durante la llamada a AddRange. –

+0

Esto resolvió mi problema, pero no estoy seguro de lo que me falta porque no veo la necesidad de este 'BaseCollection provisional '. ¿Cual es su propósito? – rtpHarry

Respuesta

7

El problema es que LINQ, a través de los métodos de extensión en IEnumerable<T>, sabe cómo crear matrices, listas y diccionarios, no sabe cómo crear su colección personalizada. Podría hacer que su colección personalizada tenga un constructor que tome un IEnumerable<T> o podría escribirle. El primero le permitiría usar el resultado de LINQ en su constructor directamente, este último le permitiría decorar la declaración LINQ con su extensión y recuperar la colección que desea. De cualquier forma, tendrá que hacer algún tipo de conversión de la colección genérica a su colección especializada, ya sea en el constructor o en la extensión. O bien, podría hacer las dos cosas ...

public static class MyExtensions 
{ 
    public static ProductCollection 
         ToProducts(this IEnumerable<Product> collection) 
    { 
      return new ProductCollection(collection); 
    } 
} 


public class ProductCollection : BaseCollection<Product> 
{ 
    ... 

    public ProductCollection(IEnumerable<Product> collection) 
       : base(collection) 
    { 
    } 

    ... 
} 


var products = (from p in HugeProductCollection 
       where p.Vendor = currentVendor 
       select p).ToProducts(); 
2

te puede sugerir una forma en la que usted no tiene que enumerar la colección 2 veces:

abstract class BaseCollection<T> : List<T> 
{ 
    public BaseCollection(IEnumerable<T> collection) 
     : base(collection) 
    { 
    } 
} 

class PruductCollection : BaseCollection<Product> 
{ 
    public PruductCollection(IEnumerable<Product> collection) 
     : base(collection) 
    { 
    } 
} 

var products = from p in HugeProductCollection 
       where p.Vendor = currentVendor 
       select p; 
PruductCollection objVendorProducts = new PruductCollection(products); 
-1

Podría este trabajo con un BindingList? ya que BindingList no tiene un constructor que tome un IEnumerable pero lo implementa.

BindingList: Colección, IBindingList, IList, ICollection, IEnumerable, ICancelAddNew, IRaiseItemChangedEvents

+0

BindingList no es realmente aplicable. El OP ya puede llenar su colección personalizada, por lo que agregar una BindingList como un paso intermedio adicional no ayudaría. – RogerN

Cuestiones relacionadas