Como limpar corretamente o objeto de interoperabilidade do Excel em C #, edição de 2012
Eu estou no processo de escrever uma aplicação em C # que irá abrir uma planilha do Excel (2007, por enquanto) via interoperabilidade, fazer alguma mágica e depois fechar. A parte "mágica" é não-trivial, portanto, este aplicativo conterá muitas referências a muitos objetos COM gerados pelo Excel.
Escrevi esse tipo de aplicativo antes (na verdade, muitas vezes), mas nunca encontrei uma abordagem confortável e de "bom cheiro" para interagir com objetos COM. O problema é, em parte, que, apesar de um estudo significativo, ainda não entendo perfeitamente o COM e, em parte, que os wrappers de interoperabilidade escondem muito do que provavelmente não deveriam estar ocultos. O fato de haver tantas sugestões diferentes e conflitantes da comunidade só piora as coisas.
Caso você não saiba do título, fiz minha pesquisa. O título alude a este post:
Como faço para limpar corretamente os objetos de interoperabilidade do Excel?
Primeiro perguntou em 2008, o conselho foi realmente útil e sólido na época (especialmente o "Nunca use 2 pontos com objetos com" bit), mas agora parece desatualizado. Em março de 2010, a equipe do Visual Studio postou um artigo no blog alertando colegas programadores queMarshal.ReleaseComObject [é] considerado perigoso. O artigo se referia a dois artigos,WebLog> ReleaseComObject do cbrumme eO mapeamento entre ponteiros de interface e wrappers de chamada de tempo de execução (RCWs), sugerindo que as pessoas têm usado o ReleaseComInterop incorretamente o tempo todo (cbrumme: "Se você é um aplicativo cliente usando um número modesto de objetos COM que são passados livremente em seu código gerenciado, você não deve usar o ReleaseComObject").
Alguém tem um exemplo de um aplicativo moderadamente complexo, de preferência usando vários segmentos, que é capaz de navegar com êxito entre vazamentos de memória (o Excel continua executando em segundo plano depois que o aplicativo foi fechado) e InvalidComObjectExceptions? Eu estou procurando por algo que permitirá que um objeto COM seja usado fora do contexto no qual ele foi criado, mas ainda pode ser limpo assim que o aplicativo terminar: um híbrido de estratégias de gerenciamento de memória que podem efetivamente transpor o gerenciado / divida não gerenciada.
Uma referência a um artigo ou tutorial que discuta uma abordagem correta para esse problema seria uma alternativa muito apreciada. Meus melhores esforços do Google-fu retornaram a abordagem aparentemente incorreta do ReleaseComInterop.
ATUALIZAR:
(Esta não é uma resposta)
Eu descobri este artigo não muito depois de postar:
VSTO e COM Interop por Jake Ginnivan
Eu pude implementar sua estratégia de agrupar objetos COM em classes "AutoCleanup" através de um método de extensão, e estou muito feliz com o resultado. Apesarele não fornece uma solução para permitir que objetos COM ultrapassem os limites do contexto em que foram criados e ainda faça uso da função ReleaseComObject, pelo menos, fornece uma solução limpa e fácil de ler.
Aqui está minha implementação:
class AutoCleanup<T> : IDisposable {
public T Resource {
get;
private set;
}
public AutoCleanup( T resource ) {
this.Resource = resource;
}
~AutoCleanup() {
this.Dispose();
}
private bool _disposed = false;
public void Dispose() {
if ( !_disposed ) {
_disposed = true;
if ( this.Resource != null &&
Marshal.IsComObject( this.Resource ) ) {
Marshal.FinalReleaseComObject( this.Resource );
} else if ( this.Resource is IDisposable ) {
( (IDisposable) this.Resource ).Dispose();
}
this.Resource = null;
}
}
}
static class ExtensionMethods {
public static AutoCleanup<T> WithComCleanup<T>( this T target ) {
return new AutoCleanup<T>( target );
}
}