office microsoft example comclass .net com interop

.net - microsoft - ¿Por qué utilizar FinalReleaseComObject en lugar de ReleaseComObject?



microsoft office interop excel 2013 (1)

Sé que la diferencia básica como ReleaseComObject solo disminuye algunos contadores en uno y FinalReleaseComObject reduce a cero.

Entonces, lo que suelo escuchar es llamar a FinalReleaseComObject porque entonces está seguro de que el objeto COM realmente se ha liberado.

Pero esto me hace preguntarme, hay un punto en este contador ¿no? ¿No estás rompiendo ese mecanismo si siempre llamas a FinalReleaseComObject ? Si ese contador no es uno antes de llamar a ReleaseComObject , ¿no hay probablemente una razón para ello?

¿Qué podría causar que sea más alto que uno cuando no debería ser?

Gracias por adelantado.

PD: Mi experiencia COM solo consiste en usar Interoperabilidad de Excel. No estoy seguro si esta pregunta es local para ese dominio (es decir, fuera de Office Interop, FinalReleaseComObject no se usa con frecuencia).

Actualización 1

El article mencionado por Dan habla sobre el uso de ReleaseComObject cuando haya terminado. Como entiendo del article , esta es la forma normal. Creo que si haces esto constantemente, debería funcionar bien. En un comentario al article el autor sugiere a alguien que llame a ReleaseComObject en un ciclo hasta que realmente se ReleaseComObject (el article es de 2006, por lo que esto es análogo a llamar a FinalReleaseComObject ). Pero también afirma que esto podría ser peligroso.

Si realmente desea que el RCW llame a Release () en un punto particular del código, puede llamar a ReleaseComObject () en un bucle hasta que el valor de retorno llegue a cero. Esto debería garantizar que el RCW llamará a Release (). Sin embargo, si lo hace, tenga cuidado, cuando las otras referencias administradas intenten usar ese RCW, causará una excepción ".

Esto me lleva a pensar que, de hecho, no es una buena idea llamar siempre a FinalReleaseComObject , ya que puede causar excepciones en otros lugares. Tal como lo veo ahora, solo debes llamar a esto si estás absolutamente seguro de que puedes hacerlo.

Aún así, tengo poca experiencia en este asunto. No sé cómo puedo estar seguro. Si el contador aumenta cuando no debería, ¿no es mejor solucionar ese problema? Si es así, entonces diría que FinalReleaseComObject es más un hack que una mejor práctica.


Algunos preámbulos ...

Un Contenedor invocable en tiempo de ejecución (RCW) solo llama a IUnknown.AddRef una vez en la interfaz COM no administrada que se ajusta. Sin embargo, un RCW también mantiene un recuento separado del número de referencias administradas que hay para el RCW. Es este conteo separado de referencias administradas el que se reduce mediante una llamada a Marshal.ReleaseComObject. Cuando el recuento de referencias administradas llega a cero, el RCW llama a IUnknown. Libere una vez en la interfaz COM no administrada.

Marshal.FinalReleaseComObject lleva el recuento de referencia administrado a cero con una sola llamada y, por lo tanto, invoca el método IUnknown.Release no administrado y envuelto inmediatamente (suponiendo que el recuento de referencias administradas no fuera cero).

Entonces, ¿por qué tienen Marshal.ReleaseComObject y Marshal.FinalReleaseComObject? Llamar a Marshal.FinalReleaseComObject simplemente evita tener que escribir un bucle que llama a Marshal.ReleaseComObject repetidamente hasta que devuelve 0 cuando desea indicar que realmente ha terminado de usar un objeto COM ahora .

¿Por qué usar Marshal.ReleaseComObject o Marshal.FinalReleaseComObject? Hay dos razones por las que soy consciente:

El primero es garantizar que los recursos no administrados (como los identificadores de archivos, memoria, etc.) utilizados por el objeto COM envuelto se liberen lo antes posible como resultado de la llamada resultante al método no administrado IUnknown.Release ().

El segundo es garantizar que el hilo que llama al método no administrado IUnknown.Release () está bajo su control, y no el hilo del finalizador.

Sin llamadas a ninguno de estos métodos de Marshal, el finalizador de RCW eventualmente llamará al método no administrado IUnknown.Release () algún tiempo después de que se haya recogido el RCW.

Para detalles corroborativos, vea la entrada del blog del Equipo de Visual C ++ article