.NET 4.5Duas novas interfaces de coleção, IReadOnlyList e IReadOnlyDictionary, foram adicionadas. Embora essas interfaces possam parecer tão mundanas à primeira vista, elas revelam histórias bastante complexas sobre retrocompatibilidade, interoperabilidade e o papel da comutabilidade.
IReadOnlyList e IReadOnlyDictionary são duas interfaces que os desenvolvedores do .NET sempre quiseram ter. Além de fornecer alguma sensação de simetria (em oposição a interfaces graváveis), uma interface somente leitura deve eliminar a implementação de métodos que apenas lançam uma exceção NotSupportedException e não fazem nada. Tudo isso não foi concluído devido a limitações de tempo.
A próxima oportunidade chegou. NET 2.0. Isso permite que a Microsoft aposente coleções fracamente tipadas e as substitua por coleções de pares fortemente tipadas. No entanto, a equipe da biblioteca base[1] mais uma vez perdeu a oportunidade de fornecer uma lista somente leitura, como escreveu Kit George,
Como pretendemos fornecer uma implementação padrão para o problema que você está falando com o Joe, em vez de fornecer uma interface, fornecemos a classe base ReadOnlyCollectionBase. No entanto, entendo por que as pessoas relutam em usá-lo, já que não é um tipo forte. Mas com a introdução dos genéricos, agora também temos o <T>ReadOnlyCollection, para que você não só tenha a mesma funcionalidade, mas também um tipo forte: ótimo!
Como a ReadOnlyCollection <T>não é uma classe lacrada, você pode escrever sua própria coleção em velocidade máxima, se necessário. Como essas coleções que criamos para isso são adaptáveis a necessidades gerais, não planejamos introduzir interfaces para esse mesmo conceito. Krzysztof Cwalina também expressou sua opinião sobre esse tema,
Quer isso pareça surpreendente ou não, IList e IList <T>são as duas interfaces que pretendemos usar para coleções somente leitura. Ambos possuem a propriedade booleana IsReadOnly, que deve retornar verdadeira quando uma coleção somente leitura implementar essa propriedade. O motivo pelo qual não queremos adicionar uma interface puramente de somente leitura é que sentimos que ela adiciona complexidade desnecessária demais à biblioteca base. Note que, em termos de complexidade, nos referimos tanto a essa nova interface quanto aos seus consumidores.
Acreditamos que, se o designer da API não se importar em verificar a propriedade IsReadOnly em tempo de execução e as exceções que ela pode lançar, então está tudo bem usar a interface IList nesse caso; Se eles estiverem dispostos a fornecer uma API personalizada realmente limpa de uma vez só, nesse caso deveriam mostrar a implementação da interface IList e publicar uma API somente leitura personalizada. O último é típico para coleções expostas a partir do modelo de objetos. Embora os desenvolvedores tenham reclamado dessa situação, as novas oportunidades oferecidas pelos genéricos superam em muito esse ponto crucial e o problema está em . NET 4 era amplamente ignorado antes. No entanto, essa decisão também gerou algumas reações, que discutiremos adiante.
Com o in. Um novo recurso empolgante no .NET 4 foi adicionado ao runtime. Em uma versão anterior. .NET, quando interfaces se tornam tipos, essas interfaces ficam excessivamente restritas. Por exemplo, mesmo que o Cliente herde de Pessoa, não é possível passar um objeto do tipo IEnumerável <Customer>como parâmetro para uma função do tipo IEnumerável<Person>. Com a adição do suporte covariante, essa restrição foi parcialmente removida.
Dizemos "parcialmente" porque, em alguns casos, as pessoas deveriam usar alguma interface com uma API rica de uma vez só, em vez de usar uma interface IEnumerable. Mesmo que a interface IList não seja covariante, uma interface de lista somente leitura deve ser. Infelizmente, . A equipe da biblioteca base do .NET novamente decidiu não corrigir essa falha.
Depois, a introdução do WinRT e o retorno do COM mudaram tudo. A interoperabilidade COM já foi uma tecnologia que os desenvolvedores usavam quando não tinham outra escolha, mas ela se tornou um . A pedra angular da programação .NET. E como o WinRT expõe as <T>interfaces IVectorView e IMapView<K, V>, portanto. .NET também deve ser ajustado de acordo.
Uma característica interessante do programa WinRT é o anúncio de APIs diferentes, mas semelhantes, para cada plataforma de desenvolvimento. Como você já deve saber, todos os nomes dos métodos são representados por camelCased [2], enquanto desenvolvedores de C++ e .NET veem os nomes dos métodos como PascalCased [3]. Outra mudança mais drástica é o mapeamento automático entre as interfaces C++ e .NET. Portanto. Desenvolvedores do .NET não precisam lidar com o namespace Windows.Foundation.Collections, apenas continuam usando o namespace System.Collections.Generic. As interfaces IVectorView <T>e IMapView<K, V> serão convertidas pelo tempo de execução em interfaces IReadOnlyList <T>e interfaces IReadOnlyDictionary<TKey, TValue>, respectivamente.
Vale notar que esses nomes de interface em C++/WinRT são mais precisos até certo ponto. Essas interfaces são usadas para representar algumas visões de uma coleção, mas a interface não garante que a coleção em si seja imutável. Mesmo entre aqueles com experiência especial. Um erro comum entre desenvolvedores .NET é assumir que o tipo ReadOnlyCollection é uma cópia de uma coleção imutável, mas na verdade é apenas um wrapper para uma coleção ativa (veja o post de Andrew Arnott com o mesmo nome para mais informações sobre coleções somente leitura, congeladas e imutáveis).
Embora a interface IList <T>tenha todos os mesmos membros da interface IReadOnlyList<T>, e todas <T>as listas do tipo IList possam ser representadas como listas somente leitura, IList <T>não herda do IReadOnlyList<T>, o que pode ser interessante de aprender. Immo Landwerth explicou,
O motivo de funcionar é que essas interfaces somente leitura são subconjuntos puros de interfaces de leitura-escrita, o que parece uma suposição razoável. Infelizmente, essa suposição não corresponde à realidade, pois cada método em cada interface no nível dos metadados tem seu próprio slot (o que faz implementações explícitas de interface funcionarem). Ou seja, a única chance de introduzir uma interface somente leitura como uma classe base de variável é recorrer a . NET 2.0, ou seja, quando foram originalmente concebidos. Uma vez totalmente implementado, a única mudança que pode fazer é adicionar marcadores covariantes e/ou inversores (representados como "in" e "out" em VB e C#).
Quando perguntado por que não existe interface IReadOnlyCollection<T>, Immo respondeu,
Consideramos esse design, mas sentimos que adicionar um tipo que fornecesse apenas o atributo Count não agregaria muito valor à biblioteca base. Na equipe da biblioteca base, acreditamos que se uma API começa em menos 1000, então nem mesmo fornecer algum valor é suficiente para justificar a adição. A justificativa para adicionar novas APIs também inclui um custo, por exemplo, os desenvolvedores terão mais conceitos para escolher. No começo, pensamos que adicionar esse tipo faria o código funcionar melhor em certos cenários onde você só quer fazer uma contagem e fazer algo interessante com ele. Por exemplo, adicionar em massa a uma coleção já existente. No entanto, nesses cenários, incentivamos as pessoas a usarem apenas a <T>interface IEnumerable, e <T>para o caso especial de ter uma instância que implementa a interface ICollection. Como todos os nossos tipos de coleção integrados implementaram essa interface, não houve ganho de desempenho nesses cenários mais comuns. Aliás, <T>o método de extensão Count() para IEnumerable também pode fazer isso. Essas novas interfaces estão disponíveis para . NET 4.5 e . NET for Windows 8。
Notas de tradução
[1] Biblioteca de Classe Base, abreviada como BCL. Para mais informações sobre a biblioteca da turma base, por favor, participe do MSDN.
[2] nomenclatura camelCased, corcoba, também conhecida como camel case inferior. O formato é que a primeira palavra começa com uma letra minúscula; A primeira letra da segunda palavra é capitalizada, por exemplo: nomenome, sobrenome.
[3] PascalCased, nomenclatura Pascal, também conhecida como caixa camelo superior. O formato é que a primeira letra de cada palavra é capitalizada, por exemplo: NomePrónome, Sobrenome, Caso Camel. |