c# - variable - Lista<BusinessObject> o BusinessObjectCollection?
generics c# (18)
Como alguien más señaló, se recomienda no exponer públicamente a la Lista, y FxCop fluctuará si lo hace. Esto incluye heredar de la lista 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 que desee su propia colección personalizada, puede mantener FxCop en silencio al heredar de Collection en lugar de List.
Antes de los genéricos de C #, todos codificaban las colecciones para sus objetos comerciales creando una base de recopilación que implementaba IEnumerable
ES DECIR:
public class CollectionBase : IEnumerable
y luego obtendrían sus colecciones de Objeto de negocio de eso.
public class BusinessObjectCollection : CollectionBase
Ahora con la clase de lista genérica, ¿alguien usa eso 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.
¿Cuál es su enfoque?
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'', lo heredo y código ese bit adicional .
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, dado que Dictionary define un método Add (clave K, valor V), es posible inicializar un diccionario utilizando esta sintaxis:
var d = new Dictionary<string, int>
{
{"hello", 0},
{"the answer to life the universe and everything is:", 42}
};
Lo mejor de la función 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 ser realmente útil si necesita crear tablas estáticas de objetos complejos. Por ejemplo, si estuvieras utilizando List<Customer>
y quisieras crear una lista estática de objetos de clientes, tendrías 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 usa 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));
}
}
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 más fácil 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 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.
Generalmente 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.
Hago exactamente lo mismo que tú Jonathan ... simplemente heredas 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.
He estado yendo y viniendo en 2 opciones:
public class BusinessObjectCollection : List<BusinessObject> {}
o métodos que solo 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 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.
Prefiero solo usar List<BusinessObject>
. Typedefing simplemente agrega una repetición innecesaria al código. List<BusinessObject>
es un tipo específico, no es simplemente cualquier objeto List
, por lo que todavía está fuertemente tipado.
Lo que es más importante, declarar algo List<BusinessObject>
hace que sea más fácil para todos los que leen el código decir qué tipos están tratando, no tienen que buscar para descubrir qué es una 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.
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 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.
Puedes usar 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 / recomendación sensato presentado por el recommended ya vinculado sobre la exposición de List como miembro público, prefiero la "tercera" manera:
Personalmente utilizo el patrón de decorador para exponer solo lo que necesito de List, 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, probablemente resumiría OrderItemCollection en IOrderItemCollection para poder intercambiar mi implementación de IOrderItemCollection en el futuro en (puedo preferir usar un objeto enumerable interno diferente como Collection o más likley para perf utilizar una colección o conjunto de Key Value Pair .
Se recommended que en las API públicas no se use List <T>, sino que se use Collection <T>
Si estás heredando de eso, deberías estar bien, afaik.
Si elige crear su propia clase de colección, debe verificar los tipos en System.Collections.ObjectModel Namespace .
El espacio de nombres define las clases base que se utilizan 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 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 el uso de 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 framework maduro de ORM? :)
Use el tipo List<BusinessObject>
donde debe declarar una lista de ellos. Sin embargo, cuando devuelva 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 quiera "agregar código personalizado" a una lista, use métodos de extensión de código en el tipo de lista. De nuevo, adjunte estos métodos al contrato más débil posible, por ej.
public static int SomeCount(this IEnumerable<BusinessObject> someList)
Por supuesto, no puede y no debe agregar estado con los métodos de extensión, de modo que si necesita agregar una nueva propiedad y un campo detrás de ella, use una subclase o una clase mejor, una clase contenedora para almacenar esto.
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.
Yo haría esto:
using BusinessObjectCollection = List<BusinessObject>;
Esto solo 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).
esta es la forma:
devolver matrices, aceptar IEnumerable<T>
=)
prueba esto:
System.Collections.ObjectModel.Collection<BusinessObject>
hace innecesario implementar un método básico como CollectionBase do
6 de 1, media docena de otra
De cualquier manera es lo mismo. Solo lo hago cuando tengo motivos para agregar código personalizado en BusinessObjectCollection.
Sin tener que devolver los métodos de carga, 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.