Estou sendo solicitado a implementar IDisposable em objetos que são 100% recursos gerenciados, que não contêm fluxos e nem grandes recursos.
Eu entendo a importância de descartar adequadamente grandes recursos e recursos não gerenciados, mas e o outro lado da equação?
Para um objeto que não se beneficia da implementação de IDisposable (pequenos objetos totalmente gerenciados) , que impacto negativo GC.SuppressFinalize pode ter, se houver?
Comentários
Resposta
O único objetivo de GC.SuppressFinalize
é:
evitar que o finalizador libere recursos não gerenciados que já foram liberados pela implementação IDisposable.Dispose.
Depois de descartar o objeto, você deve chamar GC.SuppressFinalize(this);
, como mostrado em , uma resposta à pergunta ” Quando devo usar GC.SuppressFinalize ()? “. A análise de código “ regra CA1816 também é útil.
Agora, implementando IDisposable
em objetos que não possuem recursos não gerenciados parecem bastante estranhos e questionáveis. Já que o único motivo que a pessoa deu a você foi: “é apenas a maneira que” sempre fizemos, você também faz “, em vez de fornecer dados de perfil / benchmarking que mostram que adicionar IDisposable
vai melhorar algo em um caso específico, não há motivos reais para fazer isso.
Isso causaria problemas de desempenho? É difícil dizer: dependeria de um caso específico.
Seria causa algum outro problema? Claro. Sem contar o fato de que IDisposable
é difícil de implementar, se essa prática for usada demais, o código se torna ilegível e impossível de manter:
public int ComputePrice(Rebate rebate) { using (var currentCurrency = this.User.FindCurrency()) { using (var priceWithoutRebate = this.GetPurePrice()) { using (var canApplyRebate = rebate.CanApplyTo(this)) { if (!canApplyRebate) { return priceWithoutRebate; } using (var priceWithRebate = priceWithoutRebate.Apply(rebate)) { return priceWithRebate; } } } } }
Comentários
- Bem, eu acredito que a história é que há muito tempo eles tinham alguma conexão / problemas de vazamento de stream, provavelmente devido ao código ADO.NET de comando / conexão com vazamento, e isso causou vazamentos de recursos massivos. Eles sabiam que implementar IDisposable em tudo resolveria o problema, então resolveram e funcionou. E agora eles j Basta implementá-lo na maioria dos objetos.
- @AndrewHoffman: parece uma explicação plausível. Mas ainda não ' não justifica a prática atual.
Resposta
Você não precisa usar o padrão de peso pesado (“doloroso”) Descartar + Finalizador em uma classe IDisposable, if a classe está selada e não tem recursos não gerenciados.
Nessa situação, você pode usar um subconjunto do padrão Dispose + Finalizer, que tem apenas Dispose()
, não tem finalizador e a classe está selada.
O motivo para selar a classe é evitar os problemas de “E se uma classe filha tiver recursos não gerenciados?” e “E se uma classe filha no futuro tiver recursos não gerenciados?”
Joe Duffy, anteriormente da Microsoft, tem um artigo longo (mais de 30 páginas) que discute como implementar corretamente IDisposable
, e todas as implementações de subconjunto de permutação.
Os contribuintes do artigo incluem Herb Sutter, Brian Grunkemeyer, Jeff Richter e outros luminares do C #. O artigo é muito mais detalhado do que o apresentado no MSDN.
Infelizmente, o novo mecanismo de blog de Joe Duffy não fez um bom trabalho em preservar o artigo original de 2005, por isso parece um tanto mungido. Aqui está o link: http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/
Eu gostaria de poder anexar meu documento MS-Word que contém todo o artigo de Joe Duffy de uma forma muito melhor formato. 🙁
IDisposable
neste caso melhora a pegada de memória?IDisposable
sem escrever um destruidor / finalizador. Eu não ' não sei se a pessoa que pediu para você implementarIDisposable
quis dizer que você deveria fazer um destruidor também. Obviamente, se a classe não tiver destruidor, não haverá nenhum ponto emGC.SuppressFinalize
. Se a classe tiver um destruidor, certifique-se de dizerGC.SuppressFinalize(this)
quando seuDispose
método for executado. Caso contrário, a instância não será coletada como lixo facilmente, ela será enfileirada em uma fila do finalizador e somente será coletada em uma coleta de geração 2.