Em C #, como se obtém um enumerador genérico de uma determinada matriz?
No código abaixo, MyArray
é uma matriz de MyType
objetos. Gostaria de obter MyIEnumerator
da forma indicada, mas parece que obtenho um enumerador vazio (embora o tenha confirmado MyArray.Length > 0
).
MyType[] MyArray = ... ;
IEnumerator<MyType> MyIEnumerator = MyArray.GetEnumerator() as IEnumerator<MyType>;
c#
arrays
generics
ienumerator
JaysonFix
fonte
fonte
Respostas:
Funciona em 2.0+:
Funciona em 3.5+ (LINQy sofisticado, um pouco menos eficiente):
fonte
LINQ/Cast
tem um comportamento de tempo de execução muito diferente, uma vez que cada elemento da matriz será passado através de um conjunto extra deMoveNext
eCurrent
enumerador round-trips, e isso pode afetar o desempenho se a matriz é enorme. Em qualquer caso, o problema é completamente e facilmente evitado obtendo-se o enumerador adequado em primeiro lugar (ou seja, usando um dos dois métodos mostrados em minha resposta).myArray.Cast<MyType>().GetEnumerator()
em seu loop mais interno, poderá diminuir sua velocidade significativamente, mesmo para matrizes minúsculas.Você pode decidir por si mesmo se o elenco é feio o suficiente para justificar uma chamada externa à biblioteca:
E para completar, deve-se observar também que o seguinte não está correto - e irá travar em tempo de execução - porque
T[]
escolhe a interface não genéricaIEnumerable
para sua implementação padrão (ou seja, não explícita) deGetEnumerator()
.O mistério é: por que não
SZGenericArrayEnumerator<T>
herda deSZArrayEnumerator
- uma classe interna que atualmente está marcada como 'selada' - já que isso permitiria que o enumerador genérico (covariante) fosse retornado por padrão?fonte
((IEnumerable<int>)arr)
mas apenas um conjunto de colchetes(IEnumerator<int>)arr
?Já que não gosto de lançar, uma pequena atualização:
fonte
your_array.AsEnumerable()
não seria compilado em primeiro lugar, poisAsEnumerable()
só pode ser usado em instâncias de tipos que implementamIEnumerable
.Para deixar o mais limpo possível, gosto de deixar o compilador fazer todo o trabalho. Não há casts (portanto, é realmente seguro para tipos). Nenhuma biblioteca de terceiros (System.Linq) é usada (sem sobrecarga de tempo de execução).
// E para usar o código:
Isso tira vantagem de alguma mágica do compilador que mantém tudo limpo.
O outro ponto a ser observado é que minha resposta é a única que fará a verificação em tempo de compilação.
Para qualquer uma das outras soluções, se o tipo de "arr" mudar, o código de chamada será compilado e falhará no tempo de execução, resultando em um bug de tempo de execução.
Minha resposta fará com que o código não compile e, portanto, tenho menos chance de enviar um bug no meu código, pois isso me indicaria que estou usando o tipo errado.
fonte
Foo[]
implementaIEnumerable<Foo>
, mas se isso mudar, não será detectado em tempo de compilação. Casts explícitos nunca são à prova de tempo de compilação. Em vez disso, atribua / retorne a matriz como IEnumerable <Foo> usa a conversão implícita que é à prova de tempo de compilação.var foo = (int)new object()
. Ele compila perfeitamente e falha no tempo de execução.YourArray.OfType (). GetEnumerator ();
pode ter um desempenho um pouco melhor, já que só tem que verificar o tipo, e não lançar.
fonte
OfType<..type..>()
- pelo menos no meu caso dedouble[][]
fonte
O que você pode fazer, é claro, é apenas implementar seu próprio enumerador genérico para arrays.
Isso é mais ou menos igual à implementação do .NET de SZGenericArrayEnumerator <T> conforme mencionado por Glenn Slayden. É claro que você só deve fazer isso nos casos em que vale a pena o esforço. Na maioria dos casos, não é.
fonte