Pergunta

Esta pode ser uma pergunta antiga: por que IEnumerable<T> herdar de IEnumerable?

É assim que o .NET faz, mas traz um pouco de problema. Toda vez que escrevo implementos de classe IEumerable<T>, Eu tenho que escrever dois GetEnumerator() funções, uma para IEnumerable<T> e o outro para IEnumerable.

E, IList<T> não herde do ilista.

Eu não sei por que IEnumerable<T> foi projetado de outra maneira.

Foi útil?

Solução

Direto da boca do cavalo (Hejlsberg):

Idealmente, todas as interfaces genéricas de coleção (por exemplo ICollection<T>, IList<T>) herdaria de suas contrapartes não genéricas, de modo que instâncias genéricas da interface pudessem ser usadas com código genérico e não genérico. Por exemplo, seria conveniente se um IList<T> poderia ser passado para o código que espera um IList.

Como se vê, a única interface genérica para a qual isso é possível é IEnumerable<T>, porque apenas IEnumerable<T> é contra-variante: em IEnumerable<T>, o parâmetro de tipo t é usado apenas nas posições "Saída" (valores de retorno) e não nas posições "entrada" (parâmetros). ICollection<T> e IList<T> Use t nas posições de entrada e saída, e essas interfaces são, portanto, invariantes. (Como um aparte, eles teriam sido contra-variantes se T fosse usado apenas em posições de entrada, mas isso realmente não importa aqui.)

<... Snip ...>

Então, para responder sua pergunta, IEnumerable<T> herda de IEnumerable Porque pode! :-)

Outras dicas

A resposta para IEnumerable é: "Porque isso pode sem afetar a segurança do tipo".

IEnumerable é uma interface "readonly" - então não importa que a forma genérica seja mais específica que a forma não -ngonérica. Você não quebra nada implementando os dois. IEnumerator.Current retorna object, enquanto IEnumerator<T>.Current retorna T - Tudo bem, como você sempre pode legitimamente se converter para object, embora possa significar boxe.

Compare isso com IList<T> e IList - você pode ligar Add(object) em um IList, enquanto isso pode muito bem ser inválido para qualquer particular IList<T> (qualquer outra coisa senão IList<object> na verdade).

Brad Abram's blogou com a resposta de Anders sobre esta mesma pergunta.

É para compatibilidade com versões anteriores. Se você ligar para uma função .NET 1.1 que espera uma baunilha que você possa passar no seu genérico Ienumerable.

Luckilly, o ienumerador genérico herda do iEenumerator de estilo antigo

Normalmente, implemento um método privado que retorna um enumerador e depois o passo para o método Getenumerator antigo e novo.

    private IEnumerator<string> Enumerator() {
        // ...
    }

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

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return Enumerator();
    }

Isso é para que funcione com classes que não suportam genéricas. Além disso, os genéricos do .NET não permitem que você faça coisas como elenco ilistu003Clong> como ilistau003Cint> , portanto, versões não genéricas de interfaces podem ser bastante úteis quando você precisa de uma classe ou interface base fixa.

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