2012-03-24 3 views
0

통합 문서 개체와 뭔가 다른 일을하고있는 한 구성 요소가 있으며 다른 클래스의 일부 메서드를 호출 한 메서드 본문의 중간에 있다고 가정 해 보겠습니다. 예 : COM 개체는 interop 정리를 능가합니다.

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 개체를 즉시 해제합니다.

편집 : 당신이 당신의 질문에 자세한 내용을 추가 한 후이가 .

otherComponent에는 WorkbookDocument 개체를 출시 할 필요가 없습니다. 이 두 개체는 첫 번째 개체가 소유자임을 암시하는 첫 개체에 만들어집니다. 그것이 최상위 Excel 개체를 소유 한 첫 번째 개체이기 때문에 (Application 개체가 있다고 가정) 첫 번째 개체는 otherComponent을 호출하고 WorkbookDocument을 전달한 다음 그 결과를 정리합니다.MainComponent에서 이러한 개체를 사용하지 않는다면 otherComponent 안에 Excel 관련 개체를 만들어서 정리해야합니다.

COM interop을 사용하면 COM 개체를 필요한 곳에 가까이 놓고 최대한 빨리 명시 적으로 놓아야합니다. 이는 특히 Office 응용 프로그램에 해당됩니다.

이 클래스는 COM 개체를 사용하여보다 쉽게 ​​만들었습니다.이 래퍼는 일회용이므로 using 범위가 끝나면 래퍼에서 COM 개체를 해제 할 때 COM 개체에 using(...)을 사용할 수 있습니다.

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