Por que IList não suporta AddRange

88

List.AddRange()existe, mas IList.AddRange()não.
Isso me parece estranho. Qual é a razão por trás disso?

Boris Callens
fonte

Respostas:

66

Porque uma interface deve ser fácil de implementar e não conter "tudo menos a cozinha". Se você adicionar, AddRangedeve adicionar InsertRangee RemoveRange(para simetria). Uma pergunta melhor seria por que não existem métodos de extensão para a IList<T>interface semelhantes à IEnumerable<T>interface. (métodos de extensão para in-place Sort, BinarySearch... seria útil)

xanatos
fonte
34
@ShdNx Eles não são muito triviais para implementar em termos de desempenho. Um "interno" AddRange/RemoveRange/InsertRangepode trabalhar diretamente na coleção "interna" e otimizar o Capacitygerenciamento e usar métodos como Array.Copymover blocos de dados. Um método de extensão RemoveRangeprovavelmente seria uma ordem de magnitude mais lenta queList.RemoveRange
xanatos
2
É uma pena que não houvesse (e ainda não haja) nenhuma maneira de uma IFoodeclaração de interface (por exemplo ) especificar um namespace "auxiliar" (por exemplo MyAssembly) de forma que se uma classe solicitar a implementação, IFoomas não tiver método int Bar(String), o compilador se auto- método de geração int IFoo.Bar(String p1) {return MyAssembly.ClassHelpers.IFoo.Bar(this, p1);} Se tal recurso existisse, as interfaces poderiam ter incluído mais métodos, como os AddRangeque poderiam ser implementados em termos de comportamento de base, mas que algumas implementações poderiam otimizar.
supercat
1
Eles poderiam ser implementados como métodos de extensão, dessa forma a implementação da interface não teria que implementá-los. Por que não estão?
Tom Pažourek
14
Isso não faz sentido. Uma interface abstrai uma implementação, de modo que possa haver várias implementações dos mesmos recursos básicos; não há nenhuma razão para que os recursos sejam omitidos de uma interface, porque a "implementação é difícil". Sem métodos como "AddRange" na interface, não há garantia de que o objeto subjacente os suporta e, nesse ponto, você é forçado a implementar uma extensão abaixo do ideal ou anular o propósito de usar uma interface fazendo suposições perigosas tentando cast para uma classe de implementação específica. Interfaces inativas são superutilizadas.
Triynko,
3
Deve haver a interface IRangeList suportando operações em massa, implementada apenas em algumas coleções que internamente terão a implementação ideal.
também
7

Para aqueles que desejam ter métodos de extensão para "AddRange", "Sort", ... em IList,

Abaixo está o AddRangemétodo de extensão:

 public static void AddRange<T>(this IList<T> source, IEnumerable<T> newList)
 {
     if (source == null)
     {
        throw new ArgumentNullException(nameof(source));
     }

     if (newList == null)
     {
        throw new ArgumentNullException(nameof(newList));
     }

     if (source is List<T> concreteList)
     {
        concreteList.AddRange(newList);
        return;
     }

     foreach (var element in newList)
     {
        source.Add(element);
     }
}

Criei uma pequena biblioteca que faz isso. Acho mais prático do que ter que refazer seus métodos de extensão em cada projeto.

Alguns métodos são mais lentos que List, mas fazem o trabalho.

Aqui está o GitHub para interessá-los:

Repositório IListExtension

Emilien Mathieu
fonte