Pergunta

Espero não ter batido para fazer algo tão básico.Eu poderia Google para a resposta, mas eu quero ouvir algo que não é um livro.

Eu estou escrevendo um teste de unidade para verificar que o meu IDictionary As teclas são seqüenciais.

Desde o Keys propriedade é um ICollection<T>, Eu quero enumerar a coleção e imprimir os valores de Chave para o console.

Quando tentar imprimir os valores de Chave usando um simples for loop:

for (int i = 0; i < unPivotedData.Count; i++)
{
    Console.WriteLine(unPivotedData.Keys[i]);
}

Recebi o seguinte erro de compilação:

Cannot apply indexing with [] to an expression of type 'System.Collections.Generic.ICollection<int>'

No entanto, quando eu usei o foreach loop:

foreach(int key in unPivotedData.Keys)
{
    Console.WriteLine(key);
}

Tudo funcionou muito bem.

Eu entendo o que um indexador faz e a forma como é implementado, mas como o foreach trabalho?Eu não entendo como o foreach pode trabalhar ainda o for resulta em um erro do compilador.

Estou em falta fundamental de Enumeração aqui?

Saúde!

EDITAR:Além disso, há uma diferença de desempenho entre os dois?Eu sei que eu não posso usar for com um IDictionary, mas se eu estou usando uma IList, eu posso.O for mover-se mais rapidamente do que o foreach ou seja, o ganho de desempenho insignificante

Foi útil?

Solução

foreach simplesmente precisa IEnumerable; enquanto for(a,b,c) (No seu caso) requer uma propriedade indexadora.

Quando Você ligar foreach em um objeto que implementa IEnumerable, sob o capô, ele chama GetEnumerator(), que retorna um IEnumerator objeto. Esse objeto implementa alguns membros como MoveNext() e Current. Cada iteração do foreach está realmente ligando MoveNext(), que retorna true Se o enumerador puder avançar e false se não puder (atingiu o final).

A chave aqui é que um objeto que implementa IEnumerable Não sabe quantos itens ele possui, o índice do item em que está, etc. Tudo o que sabe é que ele pode avançar para o próximo item, devolvê -lo como o item atual, até ficar sem itens.

UMA for(a,b,c) O loop, por outro lado, vai essencialmente fazer um loop para sempre - ou seja, não é limitado pela coleção que você pode estar iterando (embora na prática geralmente seja). No nível mais básico, ele executa C uma vez de cada vez e verificando se B é verdade. Se B é verdade, ele vai fazer um loop novamente. Se for falso, vai parar. Cada vez que ele faz loops, dentro do loop, você provavelmente está ligando object[number], que se seu objeto não tiver essa propriedade, é claro que falhará.

A chave aqui é que um objeto com um indexador suporta acesso aleatório - Isso significa que você pode, a qualquer momento, ligar [arbitrary index] e pegue aquele. Contraste isso com IEnumerable, que novamente só pode acessar o atual item.

Outras dicas

A coleção Keys não é indexada porque, por definição de um dicionário, a ordem dos elementos não é garantida. O que, infelizmente, também significa que o objetivo do teste de unidade que você está escrevendo é fundamentalmente falho.

Você pode pensar que a diferença entre IList<T> (que suporta indexação) e IEnumerable<T> como esta:

Se eu tenho um quarto com objectos espalhados por todo o chão, e eu pedir para você recuperar para mim todos os objetos na sala, você pode apenas ir em, começa a pegar objetos sem nenhuma ordem em particular e lançando-os para mim.A ordem não importa; o que importa é que você passar por todos os itens.Os objetos na sala, nesse sentido, poderia ser abstratamente considerado como implementar o IEnumerable interface.Então se eu jogar todos os itens de volta para a sala e pedir-lhe para fazê-lo novamente, quando você passar por eles o segundo tempo não há nenhuma garantia de que você vai buscá-las na mesma ordem.Essencialmente, este é o porque não faz sentido perguntar, "o Que é o n-ésimo item no quarto?"

Esta é uma observação importante sobre IEnumerable:embora eu nunca vi um caso onde foreach não use a mesma ordem em cada chamada, ele não tem para.

Por outro lado, se eu colocar objetos em um quarto em uma ordem específica, e peço-lhe para ir e pegá-los na mesma ordem em que coloquei os, e , em seguida, faria sentido atribuir um número para cada objeto.A pergunta "o Que é o n-ésimo item I no quarto?" realmente faz sentido nesse contexto.Assim, neste cenário os objectos do quarto pode ser pensado como a implementação da IList interface.

A foreach usa a interface ienumerable. Veja sua definição em ajuda e você terá uma ideia.

As others have stated the foreach uses the Enumerator of the collection, so

foreach(int key in unPivotedData.Keys)
{
    Console.WriteLine(key);
}

translate into something like:

IEnumerator enumerator = unPivotedData.Keys.GetEnumerator()
while(enumerator.MoveNext())
{
  Console.WriteLine(enumerator.Current);
}

as you can see there's no indexing in that. Indexing is a very different beast from iterator that can be used for iteration purposes (as you're trying in you for loop) but an iterator cannot be used for indexing only iterating

A foreach goes through the IEnumerable interface, which just provides a custom Enumerator. See http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx for info.

Basically, it acts as a custom Linked-list sort of thing, with a 'current' and a 'move next'.

Read Using foreach with Collections from the C# documentation.

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