Pergunta

Antes dos genéricos do C#, todos codificariam coleções para seus objetos de negócios criando uma base de coleção que implementasse IEnumerable

Ou seja:

public class CollectionBase : IEnumerable

e então derivariam suas coleções de objetos de negócios disso.

public class BusinessObjectCollection : CollectionBase

Agora, com a classe de lista genérica, alguém usa isso?Descobri que uso um compromisso entre as duas técnicas:

public class BusinessObjectCollection : List<BusinessObject>

Faço isso porque gosto de ter nomes fortemente digitados em vez de apenas passar listas.

O que é seu abordagem?

Foi útil?

Solução

Geralmente, prefiro usar apenas uma Lista diretamente, a menos que, por algum motivo, eu precise encapsular a estrutura de dados e fornecer um subconjunto limitado de sua funcionalidade.Isso ocorre principalmente porque, se eu não tiver uma necessidade específica de encapsulamento, fazê-lo será apenas uma perda de tempo.

No entanto, com o recurso de inicialização agregada no C# 3.0, há algumas novas situações em que eu recomendaria o uso de classes de coleção personalizadas.

Basicamente, o C# 3.0 permite qualquer classe que implemente IEnumerable e possui um método Add para usar a nova sintaxe do inicializador agregado.Por exemplo, como Dictionary define um método Add(K key, V value) é possível inicializar um dicionário usando esta sintaxe:

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

A melhor coisa sobre o recurso é que ele funciona para adicionar métodos com qualquer número de argumentos.Por exemplo, dada esta coleção:

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

    //...
}

seria possível inicializá-lo assim:

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

Isto pode ser muito útil se você precisar criar tabelas estáticas de objetos complexos.Por exemplo, se você estivesse apenas usando List<Customer> e você quisesse criar uma lista estática de objetos de cliente, teria que criá-la assim:

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")
}

Porém, se você usar uma coleção customizada, como esta:

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

Você poderia então inicializar a coleção usando esta sintaxe:

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"}
}

Isso tem a vantagem de ser mais fácil de digitar e mais fácil de ler porque não há necessidade de redigitar o nome do tipo de elemento para cada elemento.A vantagem pode ser particularmente forte se o tipo de elemento for longo ou complexo.

Dito isto, isso só será útil se você precisar de coleções estáticas de dados definidas em seu aplicativo.Alguns tipos de aplicativos, como compiladores, os utilizam o tempo todo.Outros, como aplicativos de banco de dados típicos, não o fazem porque carregam todos os seus dados de um banco de dados.

Meu conselho seria que, se você precisar definir uma coleção estática de objetos ou encapsular a interface da coleção, crie uma classe de coleção personalizada.Caso contrário, eu apenas usaria List<T> diretamente.

Outras dicas

Isso é recomendado que em APIs públicas não use List<T>, mas use Collection<T>

Se você está herdando dele, você deve ficar bem, afaik.

Eu prefiro apenas usar List<BusinessObject>.Digitá-lo apenas adiciona clichês desnecessários ao código. List<BusinessObject> é um tipo específico, não é qualquer List objeto, então ainda é fortemente digitado.

Mais importante ainda, declarar algo List<BusinessObject> torna mais fácil para todos que leem o código saber com quais tipos estão lidando, eles não precisam pesquisar para descobrir o que é um BusinessObjectCollection é e lembre-se que é apenas uma lista.Ao digitar, você precisará exigir uma convenção de (re) nomenclatura consistente que todos devem seguir para que faça sentido.

Utilize o tipo List<BusinessObject> onde você deve declarar uma lista deles.No entanto, onde você retorna uma lista de BusinessObject, considere retornar IEnumerable<T>, IList<T> ou ReadOnlyCollection<T> - ou sejadevolver o contrato mais fraco possível que satisfaça o cliente.

Onde você deseja "adicionar código personalizado" a uma lista, métodos de extensão de código no tipo de lista.Novamente, anexe esses métodos ao contrato mais fraco possível, por ex.

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

Claro, você não pode e não deve adicionar estado com métodos de extensão, então se precisar adicionar uma nova propriedade e um campo atrás dela, use uma subclasse ou melhor, uma classe wrapper para armazenar isso.

Tenho ido e voltado em 2 opções:

public class BusinessObjectCollection : List<BusinessObject> {}

ou métodos que apenas fazem o seguinte:

public IEnumerable<BusinessObject> GetBusinessObjects();

Os benefícios da primeira abordagem é que você pode alterar o armazenamento de dados subjacente sem precisar mexer nas assinaturas dos métodos.Infelizmente, se você herdar de um tipo de coleção que remove um método da implementação anterior, terá que lidar com essas situações em todo o seu código.

Você provavelmente deve evitar criar sua própria coleção para esse propósito.É muito comum querer alterar o tipo de estrutura de dados algumas vezes durante refatorações ou ao adicionar novos recursos.Com sua abordagem, você acabaria com uma classe separada para BusinessObjectList, BusinessObjectDictionary, BusinessObjectTree, etc.

Eu realmente não vejo nenhum valor em criar esta classe só porque o nome da classe é mais legível.Sim, a sintaxe do colchete angular é meio feia, mas é padrão em C++, C# e Java, então mesmo que você não escreva um código que a utilize, você vai se deparar com ela o tempo todo.

Geralmente, só deduzo minhas próprias classes de coleção se precisar "agregar valor".Por exemplo, se a própria coleção precisasse ter algumas propriedades de "metadados" marcadas junto com ela.

Eu faço exatamente a mesma coisa que você Jonathan...apenas herdar de List<T>.Você obtém o melhor dos dois mundos.Mas geralmente só faço isso quando há algum valor a agregar, como adicionar um LoadAll() método ou qualquer outra coisa.

Você pode usar ambos.Para preguiça - quero dizer produtividade - List é uma aula muito útil, também é "abrangente" e francamente cheia de membros YANGNI.Juntamente com o argumento/recomendação sensato apresentado pelo Artigo MSDN já vinculado sobre a exposição da Lista como membro público, prefiro a "terceira" forma:

Pessoalmente, uso o padrão decorador para expor apenas o que preciso da Lista, ou seja:

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

Além disso, eu provavelmente abstrairia OrderItemCollection em IOrderItemCollection para poder trocar minha implementação de IOrderItemCollection no futuro (posso preferir usar um objeto enumerável interno diferente, como Collection ou mais provavelmente para perf usar uma coleção de par de valores-chave ou conjunto .

Eu uso listas genéricas para quase todos os cenários.A única vez que eu consideraria usar uma coleção derivada seria se eu adicionasse membros específicos da coleção.No entanto, o advento do LINQ diminuiu até mesmo a necessidade disso.

6 de 1, meia dúzia de outro

De qualquer forma é a mesma coisa.Só faço isso quando tenho motivos para adicionar código personalizado ao BusinessObjectCollection.

Sem que os métodos de carregamento retornem uma lista, posso escrever mais código em uma classe genérica comum e fazê-la funcionar.Como um método Load.

Como alguém apontou, é recomendável não expor List publicamente, e o FxCop irá reclamar se você fizer isso.Isso inclui herdar de List como em:

public MyTypeCollection : List<MyType>

Na maioria dos casos, as APIs públicas exporão IList (ou ICollection ou IEnumerable) conforme apropriado.

Nos casos em que você deseja sua própria coleção personalizada, você pode manter o FxCop silencioso herdando de Collection em vez de List.

Se você optar por criar sua própria classe de coleção, verifique os tipos em Namespace System.Collections.ObjectModel.

O namespace define classes base que são criadas para facilitar aos implementadores a criação de coleções personalizadas.

Costumo fazer isso com minha própria coleção se quiser proteger o acesso à lista real.Quando você está escrevendo objetos de negócios, é provável que você precise de um gancho para saber se seu objeto está sendo adicionado/removido, nesse sentido acho que BOCollection é uma ideia melhor.Claro, se isso não for necessário, List é mais leve.Além disso, você pode querer verificar o uso de IList para fornecer uma interface de abstração adicional se precisar de algum tipo de proxy (por exemplo,uma coleção falsa aciona carregamento lento do banco de dados)

Mas...por que não considerar o Castle ActiveRecord ou qualquer outra estrutura ORM madura?:)

Na maioria das vezes eu simplesmente sigo o método List, pois ele me dá toda a funcionalidade que preciso em 90% do tempo, e quando algo 'extra' é necessário, eu herdo dele e codifico esse bit extra .

Eu faria isso:

using BusinessObjectCollection = List<BusinessObject>;

Isso apenas cria um alias em vez de um tipo completamente novo.Prefiro usar List<BusinessObject> diretamente porque me deixa livre para alterar a estrutura subjacente da coleção em algum momento no futuro sem alterar o código que a utiliza (desde que eu forneça as mesmas propriedades e métodos).

experimente isto:

System.Collections.ObjectModel.Collection<BusinessObject>

torna desnecessário implementar métodos básicos como CollectionBase.

este é o caminho:

retornar matrizes, aceitar IEnumerable<T>

=)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top