2012-03-24 15 views
0

私は、ワークブックオブジェクトで何かをしているコンポーネントがあり、そのメソッド本体の途中に別のクラスのメソッドを呼び出すことができます。例えば :COMオブジェクトexcel interop clean up

public class MainComponent 
{ 

    public void MyMainMethod() 
    { 
     OtherComponent otherComponent = new OtherComponent(); 
     Workbook document; 
     // some work with workbook object 

     // working with document and worksheet objects. 
     otherComponent.MethodCall(document); 

     // some work with workbook object and it's worksheets. 

     foreach(Worksheet sheet in document.Workheets) 
     // do something with sheet 
    } 
} 

public class OtherComponent 
{ 
    public void MethodCall(Workbook document) 
    { 
    string worksheetNames = ""; 
    foreach(Worksheet sheet in document.Worksheets) 
     worksheetNames += sheet.Name; 
    Console.WriteLine(worksheetNames); 
    } 
} 

そしてそれotherComponent.MethodCall(文書)で、私はドキュメントを使用しており、ワークシートを繰り返しています。

EDITこれは具体的な質問です。文書のReleaseCOMObjectと、otherComponent.MethodCall(ドキュメント)のワークシートを呼び出す必要がありますか?

私はこの管理されていないコードをどのように管理すればよいのか、本当に良い説明はありませんでした。 誰かが私にこれを説明できるかどうか本当に感謝します。

+0

一般に、オブジェクトを作成したメソッドは、クリーンアップを担当する必要があります。このシナリオでは、「クリーンアップ」からなるものはやや曖昧です。あなたは初期化とクリーンアップコードだけでなく、後で問題を引き起こす可能性があることについて何らかの説明を投稿するべきです。 –

答えて

4

すべてのローカルオブジェクトを作成するスコープで手動で解放する必要があります。オートメーションによるOfficeアプリケーションを使用するときは、ガベージコレクタを使用してこれらのオブジェクトをクリーンアップしないでください。たとえ正しく取得しても、時間がかかり、他のオブジェクトへの参照を保持する一時オブジェクトになることがありますあなたはすでに消えていると思います。

This is a somewhat related question Excelが非表示になっているアプリケーションからExcelを実行しようとすると、より多くの詳細が適用される場合があります。

  • すべての可能な例外を捕捉することtry..catchブロックでExcelを使用するすべての単一の関数をラップ:あなたに間違いなく関連するのです

    部分はこれです。

  • Marshal.ReleaseComObject()を呼び出して、常に必要なときにすぐに変数をnullに設定して、すべてのExcelオブジェクトを常に明示的に解放します。 finallyブロックでこれらのオブジェクトを常に解放して、失敗したExcelメソッド呼び出しがぶら下がっているCOMオブジェクトにならないようにします。
  • エラーが発生した場合は、使用しているExcelインスタンスを閉じます。 Excel関連のエラーから回復する可能性は低く、インスタンスを長くしておくほど、リソースを使用する時間が長くなります。
  • Excelを終了するときに再帰呼び出しに対してそのコードを守るようにしてください - コードをExcelのシャットダウン中に例外ハンドラでExcelをシャットダウンしようとすると、Excelが死んでしまうインスタンス。
  • Application.Quit()メソッドを呼び出した直後にGC.Collect()GC.WaitForPendingFinalizers()メソッドを呼び出して、.NET FrameworkがすべてのExcel COMオブジェクトをすぐに解放することを確認します。

編集あなたがあなたの質問に詳細を追加した後、これがあります。

otherComponentWorkbookDocumentオブジェクトをリリースする必要はありません。これらの2つのオブジェクトは、最初のオブジェクトに作成され、最初のオブジェクトが所有者であることを示します。これは、トップレベルのExcelオブジェクトを所有する最初のオブジェクトであるため(Applicationオブジェクトもあると仮定します)、最初のオブジェクトはotherComponentを呼び出し、WorkbookDocumentを渡してから、それらをクリーンアップします。MainComponentでこれらのオブジェクトを使用しない場合は、Excel関連のオブジェクトをotherComponentの中に作成して、それらをクリーンアップする必要があります。

COM相互運用機能を使用すると、COMオブジェクトを必要な場所の近くに作成し、できるだけ早く明示的に解放する必要があります。これは、特にOfficeアプリケーションの場合に当てはまります。

このクラスは、COMオブジェクトを使いやすくするために作成しました。このラッパーは使い捨てです。using(...)をCOMオブジェクトに使用できます。usingスコープがオーバーラップすると、ラッパーがCOMオブジェクトを解放します。

using System; 
using System.Runtime.InteropServices; 

namespace COMHelper 
{ 
    /// <summary> 
    /// Disposable wrapper for COM interface pointers. 
    /// </summary> 
    /// <typeparam name="T">COM interface type to wrap.</typeparam> 
    public class ComPtr<T> : IDisposable 
    { 
     private object m_oObject; 
     private bool m_bDisposeDone = false; 

     /// <summary> 
     /// Constructor 
     /// </summary> 
     /// <param name="oObject"></param> 
     public ComPtr (T oObject) 
     { 
      if (oObject == null) 
       throw (new ArgumentNullException ("Invalid reference for ComPtr (cannot be null)")); 

      if (!(Marshal.IsComObject (oObject))) 
       throw (new ArgumentException ("Invalid type for ComPtr (must be a COM interface pointer)")); 

      m_oObject = oObject; 
     } 

     /// <summary> 
     /// Constructor 
     /// </summary> 
     /// <param name="oObject"></param> 
     public ComPtr (object oObject) : this ((T) oObject) 
     { 
     } 

     /// <summary> 
     /// Destructor 
     /// </summary> 
     ~ComPtr() 
     { 
      Dispose (false); 
     } 

     /// <summary> 
     /// Returns the wrapped object. 
     /// </summary> 
     public T Object 
     { 
      get 
      { 
       return ((T) m_oObject); 
      } 
     } 

     /// <summary> 
     /// Implicit cast to type T. 
     /// </summary> 
     /// <param name="oObject">Object to cast.</param> 
     /// <returns>Returns the ComPtr object cast to type T.</returns> 
     public static implicit operator T (ComPtr<T> oObject) 
     { 
      return (oObject.Object); 
     } 

     /// <summary> 
     /// Frees up resources. 
     /// </summary> 
     public void Dispose() 
     { 
      Dispose (true); 
      GC.SuppressFinalize (this); 
     } 

     /// <summary> 
     /// Frees up resurces used by the object. 
     /// </summary> 
     /// <param name="bDispose">When false, the function is called from the destructor.</param> 
     protected void Dispose (bool bDispose) 
     { 
      try 
      { 
       if (!m_bDisposeDone && (m_oObject != null)) 
       { 
        Marshal.ReleaseComObject (m_oObject); 
        m_oObject = null; 
       } 
      } 
      finally 
      { 
       m_bDisposeDone = true; 
      } 
     } 
    } 
} 
+0

Upvoted、良い答え。 「ComPtr 」という名前を悪用するのはちょっとだと思いますが。 (そしてハンガリー表記) –

+0

@RitchMelton投票ありがとうございました。なぜあなたは 'ComPtr 'を使って名前を濫用していると思いますか? – xxbbcc

関連する問題