2008-08-22 9 views
45

Antes de C# genéricos, todo el mundo colecciones para codificar sus objetos de negocio mediante la creación de una base de colección que implementa IEnumerable¿Lista <BusinessObject> o BusinessObjectCollection?

IE:

public class CollectionBase : IEnumerable 

y luego se derivaría sus colecciones de objetos de negocios de eso.

public class BusinessObjectCollection : CollectionBase 

Ahora, con la clase de lista genérica, ¿alguien usa eso en su lugar? Me he dado cuenta que yo uso un compromiso de las dos técnicas:

public class BusinessObjectCollection : List<BusinessObject> 

Hago esto porque me gusta tener nombres inflexible en vez de pasar alrededor de Listas.

¿Cuál es su enfoque?

Respuesta

49

Generalmente estoy en el campo de simplemente usar una lista directamente, a menos que por alguna razón necesite encapsular la estructura de datos y proporcionar un subconjunto limitado de su funcionalidad. Esto es principalmente porque si no tengo una necesidad específica de encapsulación, hacerlo es solo una pérdida de tiempo.

Sin embargo, con la característica de inicialización agregada en C# 3.0, hay algunas situaciones nuevas en las que recomendaría usar clases de colección personalizadas.

Básicamente, C# 3.0 permite cualquier clase que implemente IEnumerable y tiene un método Add para usar la nueva sintaxis del inicializador agregado. Por ejemplo, debido diccionario define un método Add (clave K, el valor V) es posible inicializar un diccionario con esta sintaxis:

var d = new Dictionary<string, int> 
{ 
    {"hello", 0}, 
    {"the answer to life the universe and everything is:", 42} 
}; 

La gran cosa acerca de la característica es que funciona con los métodos add con cualquier número de argumentos. Por ejemplo, dada esta colección:

class c1 : IEnumerable 
{ 
    void Add(int x1, int x2, int x3) 
    { 
     //... 
    } 

    //... 
} 

sería posible inicializar que de este modo:

var x = new c1 
{ 
    {1,2,3}, 
    {4,5,6} 
} 

Esto puede ser muy útil si se necesita para crear tablas estáticas de objetos complejos. Por ejemplo, si se acaba utilizando List<Customer> y desea crear una lista estática de los objetos del cliente tendría que crearlo, así:

var x = new List<Customer> 
{ 
    new Customer("Scott Wisniewski", "555-555-5555", "Seattle", "WA"), 
    new Customer("John Doe", "555-555-1234", "Los Angeles", "CA"), 
    new Customer("Michael Scott", "555-555-8769", "Scranton PA"), 
    new Customer("Ali G", "", "Staines", "UK") 
} 

Sin embargo, si se utiliza una colección personalizada, como éste:

class CustomerList : List<Customer> 
{ 
    public void Add(string name, string phoneNumber, string city, string stateOrCountry) 
    { 
     Add(new Customer(name, phoneNumber, city, stateOrCounter)); 
    } 
} 

a continuación, puede inicializar la colección con esta sintaxis:

var customers = new CustomerList 
{ 
    {"Scott Wisniewski", "555-555-5555", "Seattle", "WA"}, 
    {"John Doe", "555-555-1234", "Los Angeles", "CA"}, 
    {"Michael Scott", "555-555-8769", "Scranton PA"}, 
    {"Ali G", "", "Staines", "UK"} 
} 

esto tiene la ventaja de ser más fácil de escribir y de leer sea más fácil porque no es necesario volver a escribir el nombre del tipo de elemento para cada elemento. La ventaja puede ser particularmente fuerte si el tipo de elemento es largo o complejo.

Dicho esto, esto solo es útil si necesita colecciones estáticas de datos definidos en su aplicación. Algunos tipos de aplicaciones, como los compiladores, los usan todo el tiempo. Otros, como las aplicaciones de bases de datos típicas, no lo hacen porque cargan todos sus datos desde una base de datos.

Mi consejo sería que si necesita definir una colección estática de objetos o si necesita encapsular la interfaz de colección, cree una clase de colección personalizada.De lo contrario, simplemente usaría List<T> directamente.

2

En general, solo obtengo mis propias clases de colección si necesito "agregar valor". Al igual que si la colección en sí necesitara tener algunas propiedades de "metadatos" etiquetándola.

4

He estado yendo de ida y vuelta en 2 opciones:

public class BusinessObjectCollection : List<BusinessObject> {} 

o métodos que acaba de hacer lo siguiente:

public IEnumerable<BusinessObject> GetBusinessObjects(); 

Los beneficios del primer método es que se puede cambiar el almacén de datos subyacente sin tener que meterse con las firmas de métodos. Desafortunadamente, si heredas de un tipo de colección que elimina un método de la implementación anterior, entonces tendrás que lidiar con esas situaciones en todo tu código.

3

Hago exactamente lo mismo que usted Jonathan ... simplemente herede de List<T>. Obtienes lo mejor de ambos mundos. Pero generalmente solo lo hago cuando hay algún valor que agregar, como agregar un método LoadAll() o lo que sea.

+0

Puede hacer LoadAll() como un método de extensión que cuelga de la lista . Eso le daría LoadAll() en cada Lista/Colección y podría leer desde cualquier IEnumerable ... algunas personas podrían decir que esto es un abuso de los métodos de extensión. Pero digo que te permite actuar como si tuvieras herencia múltiple. –

+0

Buena idea, aunque mi método LoadAll() no es realmente genérico. Se carga desde diferentes tablas dependiendo del tipo de objeto subyacente. Puede haber una manera de hacerlo genéricamente, pero realmente no he investigado eso hasta ahora. – jeremcc

0

6 de 1, media docena de otro

cualquier manera su la misma cosa. Solo lo hago cuando tengo motivos para agregar código personalizado en BusinessObjectCollection.

Sin tener métodos de carga devolver una lista me permite escribir más código en una clase genérica común y hacer que funcione. Tal como un método de carga.

9

Prefiero usar List<BusinessObject>. Typedefing simplemente agrega una repetición innecesaria al código. List<BusinessObject> es un tipo específico, no es cualquier objeto List, por lo que todavía está fuertemente tipado.

Más importante aún, declarar algo List<BusinessObject> hace que sea más fácil para todos leer el código decir qué tipos están tratando, no tienen que buscar para descubrir qué es BusinessObjectCollection y luego recordar que es solo una lista . Al eliminar el tipo, tendrá que exigir una convención de nombres (re) consistente que todos tengan que seguir para que tenga sentido.

3

Probablemente deba evitar crear su propia colección para tal fin.Es bastante común querer cambiar el tipo de estructura de datos varias veces durante las refactorizaciones o al agregar nuevas características. Con su enfoque, terminaría con una clase separada para BusinessObjectList, BusinessObjectDictionary, BusinessObjectTree, etc.

Realmente no veo ningún valor al crear esta clase solo porque el nombre de clase es más legible. Sí, la sintaxis del paréntesis angular es fea, pero es estándar en C++, C# y Java, por lo que incluso si no escribes el código que la usa, te encontrarás con ella todo el tiempo.

14

Es recommended que en la API pública es no utilizar la Lista <T>, sino utilizar Colección <T>

Si está heredando de él sin embargo, que debe estar bien, que yo sepa.

1

Utilizo listas genéricas para casi todos los escenarios. La única vez que consideraría usar una colección derivada más es si agrego miembros específicos de la colección. Sin embargo, la llegada de LINQ ha disminuido la necesidad de incluso eso.

-1

esta es la forma:

matrices de retorno, aceptar IEnumerable<T>

=)

+1

acepta IEnumerable , devuelve IEnumerable o ReadOnlyCollection pero nunca una matriz. Lea esto: http://blogs.msdn.com/ericlippert/archive/2008/09/22/arrays-considered-somewhat-harmful.aspx! –

+0

Lo bueno de devolver IEnumerable es que puede agregar fácilmente lazy eval a toda su aplicación. –

0

Como lo indicó otra persona, se recomienda no exponer Lista públicamente, y FxCop se whinge si lo hace asi que. Esto incluye la herencia de lista como en:

public MyTypeCollection : List<MyType> 

En la mayoría de los casos API públicas expondrá IList (o ICollection o IEnumerable) según corresponda.

En los casos en que desee su propia colección personalizada, puede mantener FxCop en silencio al heredar de Collection en lugar de List.

0

Si elige crear su propia clase de colección, debe consultar los tipos en System.Collections.ObjectModel Namespace.

El espacio de nombre define las clases base que thare están destinadas a facilitar a los implementadores la creación de colecciones personalizadas.

0

Tiendo a hacerlo con mi propia colección si quiero proteger el acceso a la lista real. Cuando escribes objetos comerciales, es probable que necesites un gancho para saber si tu objeto se agrega o quita, en tal sentido, creo que BOCollection es una mejor idea. Por supuesto, si eso no se requiere, List es más liviano. También es posible que desee comprobar utilizando IList para proporcionar una interfaz de abstracción adicional si necesita algún tipo de proxy (por ejemplo, una colección falsa desencadena la carga lenta de la base de datos)

Pero ... ¿por qué no considerar Castle ActiveRecord o cualquier otro marco ORM maduro ? :)

0

En la mayoría de las veces simplemente uso el modo Lista, ya que me da toda la funcionalidad que necesito en el 90% del tiempo, y cuando se necesita algo 'extra', heredo de él y codifica ese bit adicional.

0

Me gustaría hacer esto:

using BusinessObjectCollection = List<BusinessObject>; 

Esto sólo crea un alias en lugar de un tipo completamente nuevo. Prefiero usar List < BusinessObject> directamente porque me deja libre para cambiar la estructura subyacente de la colección en algún momento en el futuro sin cambiar el código que la usa (siempre que proporcione las mismas propiedades y métodos).

0

probar este:

System.Collections.ObjectModel.Collection<BusinessObject> 

se hace innecesaria para poner en práctica el método básico como CollectionBase hacer

2

Puede utilizar ambos. Para la pereza, me refiero a la productividad, List es una clase muy útil, también es "integral" y francamente llena de miembros de YANGNI.Junto con el argumento sensato/recomendación presentada por el MSDN article ya ligado al exponer lista como un miembro del público, prefiero el "tercer" camino:

Personalmente utilizo el patrón decorador para exponer sólo lo que necesito de la lista, es decir:

public OrderItemCollection : IEnumerable<OrderItem> 
{ 
    private readonly List<OrderItem> _orderItems = new List<OrderItem>(); 

    void Add(OrderItem item) 
    { 
     _orderItems.Add(item) 
    } 

    //implement only the list members, which are required from your domain. 
    //ie. sum items, calculate weight etc... 

    private IEnumerator<string> Enumerator() { 
     return _orderItems.GetEnumerator(); 
    } 

    public IEnumerator<string> GetEnumerator() { 
     return Enumerator(); 
    }  
} 

más aún me OrderItemCollection probablemente abstracta en IOrderItemCollection para que pueda cambiar mi implementación de IOrderItemCollection más en el futuro (I puede preferir utilizar un objeto enumerable interior diferente, como colección o más likley para uso perf una colección o conjunto de pares de valores clave

4

Use el tipo List<BusinessObject> donde tiene que declarar una lista de ellos. Sin embargo, donde devuelve una lista de BusinessObject, considere devolver IEnumerable<T>, IList<T> o ReadOnlyCollection<T> - es decir, devolver el contrato más débil posible que satisfaga al cliente.

Donde desea "agregar código personalizado" a una lista, métodos de extensión de código en el tipo de lista. Una vez más, adjunte estos métodos al contrato más débil posible, p.

public static int SomeCount(this IEnumerable<BusinessObject> someList) 

Por supuesto, no puede y no debe agregar el estado con los métodos de extensión, por lo que si es necesario agregar una nueva propiedad y un campo detrás de él, utiliza una subclase o mejor, una clase contenedora para almacenar esta.

Cuestiones relacionadas