Por que IEnumerator herdam IDisposable enquanto o IEnumerator não-genérico não?

StackOverflow https://stackoverflow.com/questions/232558

  •  04-07-2019
  •  | 
  •  

Pergunta

Eu observei que as herda IEnumerator<T> genéricos de IDisposable, mas a interface não genérica IEnumerator não. Por que é projetado desta forma?

Normalmente, usamos instrução foreach para percorrer uma instância IEnumerator<T>. O código gerado de foreach, na verdade, tem-tentar finalmente bloquear o que invoca Descarte () em finalmente.

Foi útil?

Solução

Basicamente, foi um descuido. No C # 1.0, foreach não chamado Dispose 1 . Com C # 1.2 (introduzido no VS2003 - não há 1.1, bizarramente) foreach começou a verificar no bloco finally ou não o iterador implementado IDisposable - eles tinham que fazer isso dessa forma, porque retrospectivamente fazendo IEnumerator estender IDisposable teria quebrado a implementação de todos de IEnumerator. Se tivessem trabalhado para fora que é útil para foreach de dispor de iteradores, em primeiro lugar, tenho certeza IEnumerator teria IDisposable estendida.

Quando C # 2.0 e .NET 2.0 saiu, no entanto, tiveram uma nova oportunidade - nova interface, novos herança. Faz muito mais sentido ter a interface estender IDisposable de modo que você não precisa de um check-tempo de execução no bloco finally, e agora o compilador sabe que se o iterador é um IEnumerator<T> pode emitir uma chamada incondicional de Dispose.

EDIT: É incrivelmente útil para Dispose a ser chamado no final da iteração (no entanto, termina). Isso significa que o iterador pode segurar recursos - o que o torna viável para que, por exemplo, ler um arquivo linha por linha. Iterator blocos gerar implementações Dispose que se certificar de que todos os blocos finally relevantes para o "ponto atual de execução" do iterador são executados quando é descartado -. Assim você pode escrever código normal dentro do iterador e clean-up deve acontecer de forma adequada


1 para trás Olhando para a especificação 1.0, que já foi especificado. Eu ainda não ter sido capaz de verificar esta afirmação anterior de que a implementação 1.0 não chamar Dispose.

Outras dicas

IEnumerable não herda IDisposable. IEnumerator herda IDisposable no entanto, enquanto o IEnumerator não-genérico não. Mesmo quando você usa foreach para um IEnumerable não genérica (que retorna IEnumerator), o compilador ainda irá gerar um cheque de IDisposable e chamar Dispose () se os implementos enumerador a interface.

Eu acho que o genérico Enumerator herda de IDisposable então não não precisa ser um tempo de execução tipo check-lo pode ir em frente e chamar Dispose (), que deve ter um melhor desempenho, uma vez que pode ser provavelmente ser otimizado embora, se o entrevistador tem um método vazio Descarte ().

Eu sei que esta é uma discussão antiga, mas eu reasontly escreveu uma biblioteca onde eu costumava IEnumerable de T / IEnumerator de T onde os usuários da biblioteca poderia implementar iteradores personalizados devem apenas implementar IEnumerator de t.

Eu achei muito estranho que IEnumerator da T iria herdar de IDisposable. Nós implementamos IDisposable se queremos liberar recursos unmanged certo? Por isso, só seria relevante para recenseadores que realmente detêm recursos não gerenciados - como um fluxo de IO etc. Porque não basta permitir que os usuários implementar tanto IEnumerator de T e IDisposable em seu entrevistador se faz sentido? Em meu livro isso viola o princípio da responsabilidade individual - Por que misturar lógica recenseador e objetos eliminação.

O IEnumerable` herdar IDisposing? De acordo com o refletor .NET ou MSDN . Tem certeza de que não está confundindo-a com IEnumerator ? Que usa IDisposing porque só para enumerar uma coleção e não significava para a longevidade.

Um pouco difícil de ser definitivo sobre isso, a não ser que você consiga obter uma resposta do próprio AndersH, ou alguém próximo a ele.

No entanto, o meu palpite é que ele se relaciona com a palavra-chave "rendimento" que foi introduzido em C #, ao mesmo tempo. Se você olhar para o código gerado pelo compilador quando "rendimento retorno x" é usado, você verá o método embrulhado em uma classe auxiliar que implementa IEnumerator; tendo IEnumerator descerá do garante IDisposable que ele pode limpar quando enumeração está completa.

IIRC A coisa toda sobre ter IEnumerable<T> e IEnumerable é resultado de IEnumerable predating coisas modelo de .Net. Eu suspeito que sua pergunta é da mesma forma.

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