2010-08-29 7 views
1

Étant donné le code suivant, la méthode ReleaseCOMObj() publiera-t-elle l'objet COM d'origine ou le créera-t-il implicitement et le relâchera-t-il?Puis-je créer une méthode généralisée pour libérer des objets COM?

private void TestRelease() 
{ 
    Excel.Workbook workbook = excel.ActiveWorkbook; 
    // do stuff 
    ReleaseComObj(workbook); 
} 

private static void ReleaseComObj(Object obj) 
{ 
    if (obj != null) 
    { 
     Marshal.ReleaseComObject(obj); 
     obj = null; 
    } 
} 

Mise à jour: méthode modifiée à l'électricité statique. Voir Passing COM objects as parameters in C# pour une explication sur la raison pour laquelle le paramètre Object ne peut pas être ref Object obj.

+0

Cela fonctionne rarement dans la pratique. Faites un peu d'interopérabilité non-trivial sur le classeur et vous créerez beaucoup de nombre de références cachées supplémentaires. Faites confiance au garbage collector. –

Répondre

1

C# parameters are passed by reference. Par conséquent, il libérera l'objet COM d'origine, mais il ne définira pas la variable d'origine sur null.

Pour définir la variable d'origine sur null, remplacez-la par un paramètre ref, qui transmet une variable par référence. (et appelez-le avec le mot-clé ref)

En outre, en passant, la méthode devrait être static, car il n'utilise pas this.

+0

"il va libérer l'objet COM d'origine, mais il ne définira pas la variable d'origine à null." C'est l'information clé que je cherchais. – CtrlDot

1

Si vous souhaitez définir la référence à null, vous pouvez utiliser une méthode générique comme:

private static void ReleaseComObj<T>(ref T obj) where T:class { 
     if (obj != null) { 
      Marshal.ReleaseComObject(obj); 
      obj = null; 
     } 
    } 

Bien que le réglage de la référence à NULL n'est pas nécessaire. L'objet COM sera libéré dans tous les cas. Voir la documentation pour RealeaseComObject(). Vous pouvez également envisager d'appeler FinalReleaseComObject().

Vous pouvez également créer un objet wrapper implémentant IDisposable et utiliser un bloc using pour que l'objet COM soit libéré même s'il existe une exception.

class ComObjectCleanUp : IDisposable { 

    private T obj; 

    public ComObjectCleanUp(T obj) { 
     this.obj = obj; 
    } 

    public void Dispose() { 
     if (obj != null) 
      Marshal.FinalReleaseComObject(obj); 
    } 
} 

Et votre code devient:

private void TestRelease() 
{ 
    Excel.Workbook workbook = excel.ActiveWorkbook; 
    using (var c = new ComObjectCleanUp(workbook)) 
    { 
     // do stuff 
    } 
} 

Bien que je dois admettre que ce n'est pas très jolie, surtout compte tenu du nombre d'objets COM vous référence grâce à l'automatisation de bureau, mais il est une idée de toute façon.

+1

C'est une solution intelligente, mais à la fin je suis allé juste avec un extrait de code w/raccourci: if ($ obj $! = Null) {Marshal.ReleaseComObject ($ obj $); } – CtrlDot