Pregunta

Antes de los genéricos de C#, todos codificaban colecciones para sus objetos comerciales creando una base de colecciones que implementaba IEnumerable.

ES DECIR:

public class CollectionBase : IEnumerable

y luego derivarían sus colecciones de objetos de negocio a partir de eso.

public class BusinessObjectCollection : CollectionBase

Ahora, con la clase de lista genérica, ¿alguien la usa en su lugar?Descubrí que utilizo un compromiso de las dos técnicas:

public class BusinessObjectCollection : List<BusinessObject>

Hago esto porque me gusta tener nombres fuertemente tipados en lugar de simplemente pasar Listas.

Qué es su ¿acercarse?

¿Fue útil?

Solución

Generalmente prefiero 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 se debe principalmente a que si no tengo una necesidad específica de encapsulación, hacerlo es simplemente 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 el uso de clases de colección personalizadas.

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

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

Lo mejor de esta característica es que funciona para agregar métodos con cualquier cantidad de argumentos.Por ejemplo, dada esta colección:

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

    //...
}

sería posible inicializarlo así:

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

Esto puede resultar realmente útil si necesita crear tablas estáticas de objetos complejos.Por ejemplo, si solo estuvieras usando List<Customer> y desea crear una lista estática de objetos de clientes, tendría que crearla 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 utiliza una colección personalizada, como esta:

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

Luego podrías inicializar la colección usando 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 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 sólo es útil si necesita colecciones estáticas de datos definidas en su aplicación.Algunos tipos de aplicaciones, como los compiladores, las utilizan todo el tiempo.Otras, 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 encapsular la interfaz de la colección, cree una clase de colección personalizada.De lo contrario, simplemente usaría List<T> directamente.

Otros consejos

Es recomendado que en las API públicas no usar List<T>, sino usar Collection<T>

Sin embargo, si lo heredas, deberías estar bien, que yo sepa.

Prefiero simplemente usar List<BusinessObject>.Definirlo simplemente agrega un texto repetitivo innecesario al código. List<BusinessObject> es un tipo específico, no es cualquiera List objeto, 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 los que leen el código saber con qué tipos están tratando, no tienen que buscar para descubrir qué BusinessObjectCollection es y luego recuerda que es solo una lista.Al escribir, deberá exigir una convención de (re)nombramiento consistente que todos deben seguir para que tenga sentido.

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

Cuando desee "agregar código personalizado" a una lista, codifique los métodos de extensión en el tipo de lista.Nuevamente, adjunte estos métodos al contrato más débil posible, p.

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

Por supuesto, no puedes ni debes agregar estado con métodos de extensión, por lo que si necesitas agregar una nueva propiedad y un campo detrás de ella, usa una subclase o mejor, una clase contenedora para almacenar esto.

He estado yendo y viniendo sobre 2 opciones:

public class BusinessObjectCollection : List<BusinessObject> {}

o métodos que simplemente hacen lo siguiente:

public IEnumerable<BusinessObject> GetBusinessObjects();

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

Probablemente deberías evitar crear tu propia colección para ese propósito.Es bastante común querer cambiar el tipo de estructura de datos varias veces durante las refactorizaciones o al agregar nuevas funciones.Con su enfoque, terminaría con una clase separada para BusinessObjectList, BusinessObjectDictionary, BusinessObjectTree, etc.

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

Generalmente sólo obtengo mis propias clases de colección si necesito "agregar valor".Por ejemplo, si la colección en sí necesitara tener algunas propiedades de "metadatos" etiquetadas junto con ella.

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

Puedes usar ambos.Para la pereza, me refiero a la productividad, List es una clase muy útil, también es "completa" y, francamente, está llena de miembros YANGNI.Junto con el sensato argumento/recomendación presentado por el artículo de MSDN ya vinculado sobre la exposición de List como miembro público, prefiero la "tercera" forma:

Personalmente uso el patrón decorador para exponer solo 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();
    }    
}

Además, probablemente abstraería OrderItemCollection en IOrderItemCollection para poder cambiar mi implementación de IOrderItemCollection en el futuro (tal vez prefiera usar un objeto enumerable interno diferente, como Colección o, más probablemente, para usar de manera eficiente una colección o conjunto de pares clave-valor .

Utilizo listas genéricas para casi todos los escenarios.El único momento en el que consideraría usar una colección derivada es si agrego miembros específicos de la colección.Sin embargo, la llegada de LINQ ha disminuido la necesidad incluso de eso.

6 de 1, media docena de otro

De cualquier manera es lo mismo.Solo lo hago cuando tengo motivos para agregar código personalizado a 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.Como un método de carga.

Como alguien más señaló, se recomienda no exponer a List públicamente, y FxCop se quejará si lo hace.Esto incluye heredar de List como en:

public MyTypeCollection : List<MyType>

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

En los casos en los que desee su propia colección personalizada, puede mantener FxCop en silencio heredando de Colección en lugar de Lista.

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

El espacio de nombres define clases base que se crean para facilitar a los implementadores la creación de colecciones personalizadas.

Tiendo a hacerlo con mi propia colección si quiero proteger el acceso a la lista real.Cuando escribe objetos comerciales, es posible que necesite un gancho para saber si su objeto se está agregando o eliminando, en ese sentido creo que BOCollection es una mejor idea.Por supuesto, si eso no es necesario, List es más liviano.También es posible que desee verificar el uso de IList para proporcionar una interfaz de abstracción adicional si necesita algún tipo de proxy (p. ej.una colección falsa desencadena una carga diferida desde la base de datos)

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

La mayor parte del tiempo simplemente sigo el modo Lista, ya que me brinda toda la funcionalidad que necesito el 90% del tiempo, y cuando se necesita algo "extra", lo heredo y codifico ese bit extra. .

Yo haría esto:

using BusinessObjectCollection = List<BusinessObject>;

Esto simplemente crea un alias en lugar de un tipo completamente nuevo.Lo prefiero a 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).

prueba esto:

System.Collections.ObjectModel.Collection<BusinessObject>

hace innecesario implementar un método básico como lo hace CollectionBase

esta es la forma:

devolver matrices, aceptar IEnumerable<T>

=)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top