Se me pide que implemente IDisposable en objetos que son 100% recursos administrados, que no contienen flujos ni grandes recursos.
Entiendo la importancia de disponer adecuadamente de grandes recursos y recursos no administrados, pero ¿qué pasa con el otro lado de la ecuación?
Para un objeto que no se beneficia de implementar IDisposable (pequeños objetos completamente administrados) , ¿qué impacto negativo puede tener GC.SuppressFinalize, si lo hubiera?
Comentarios
Responder
El único objetivo de GC.SuppressFinalize
es:
evitar que el finalizador libere recursos no administrados que ya han sido liberados por la implementación IDisposable.Dispose.
Una vez que haya eliminado el objeto, debería llamar a GC.SuppressFinalize(this);
, como se muestra en una respuesta a la pregunta » ¿Cuándo debería usar GC.SuppressFinalize ()? «. La regla de análisis de código « CA1816 también es útil.
Ahora, implementando IDisposable
en los objetos que no tienen recursos no administrados se ven bastante raros y cuestionables. Dado que la única razón que le dio la persona fue: «es la forma en que» siempre lo hemos hecho, usted también lo hace «, en lugar de proporcionar datos de evaluación comparativa / perfiles que muestren que agregar IDisposable
mejorará algo en un caso específico, no hay razones reales para hacerlo.
¿Causaría problemas de rendimiento? Difícil de decir: dependería del caso particular.
¿ ¿Causa algún otro problema? Por supuesto. Sin contar el hecho de que IDisposable
es doloroso de implementar, si esta práctica se usa demasiado, el código se vuelve ilegible e imposible de mantener:
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; } } } } }
Comentarios
- Bueno, creo que la historia es que hace mucho tiempo, tenían alguna conexión / problemas de fugas de flujo, probablemente debido a una conexión / comando con fugas en el código ADO.NET, y esto causó fugas masivas de recursos. Sabían que implementar IDisposable en todo resolvería el problema, así que lo hicieron, y funcionó. Y ahora j Usemos para implementarlo en la mayoría de los objetos.
- @AndrewHoffman: parece una explicación plausible. Pero todavía no ' justifica la práctica actual.
Respuesta
No es necesario que utilice el patrón Dispose + Finalizer pesado («doloroso») en una clase IDisposable, si la clase está sellada y la clase no tiene recursos no administrados.
En esa situación, puede usar un subconjunto del patrón Dispose + Finalizer, que solo tiene public Dispose()
, no tiene finalizador y la clase está sellada.
La razón para sellar la clase es evitar los problemas de «¿Qué pasa si una clase secundaria tiene recursos no administrados?» y «¿Qué pasa si una clase secundaria en el futuro tendrá recursos no administrados?»
Joe Duffy, anteriormente de Microsoft, tiene un artículo extenso (más de 30 páginas) que analiza cómo implementar correctamente IDisposable
, y todas las implementaciones de subconjuntos de permutación.
Los colaboradores del artículo incluyen a Herb Sutter, Brian Grunkemeyer, Jeff Richter y otras luminarias de C #. El artículo es mucho más detallado que lo que se presenta en MSDN.
Por desgracia, el nuevo motor de blogs de Joe Duffy no ha hecho un buen trabajo conservando el artículo original de 2005, por lo que parece un poco molesto. Aquí está el enlace: http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/
Me gustaría poder adjuntar mi documento de MS-Word que tiene la totalidad del artículo de Joe Duffy de una manera mucho mejor formato. 🙁
IDisposable
en este caso mejora la huella de memoria?IDisposable
sin escribir un destructor / finalizador. No ' sé si la persona que te pidió que implementarasIDisposable
quiso decir que también debías hacer un destructor. Por supuesto, si la clase no tiene destructor, no tiene sentidoGC.SuppressFinalize
. Si la clase tiene un destructor, asegúrese de decirGC.SuppressFinalize(this)
cuando se haya ejecutado su métodoDispose
. De lo contrario, la instancia no se recopilará fácilmente, se pondrá en cola en una cola de finalizador y solo se recopilará en una recopilación de generación 2.