2010-05-04 21 views
11

सभी इन सवालों के:आवरण वस्तुओं का उपयोग करना ठीक एक्सेल इंटरॉप साफ करने के लिए वस्तुओं

समस्या यह है कि सी # एक्सेल जारी नहीं करता है के साथ संघर्ष COM का उपयोग करने के बाद ठीक से वस्तुओं। इस मुद्दे के आसपास काम करने के मुख्य रूप से दो दिशाएं हैं:

  1. Excel का उपयोग नहीं होने पर एक्सेल प्रक्रिया को मार दें।
  2. स्पष्ट रूप से पहले एक चर के लिए उपयोग की जाने वाली प्रत्येक COM ऑब्जेक्ट को स्पष्ट रूप से असाइन करने के लिए सावधानी बरतें और अंततः गारंटी दें कि मार्शल। रिलीज कॉम ऑब्जेक्ट प्रत्येक पर निष्पादित किया जाता है।

कुछ ने कहा है कि 2 बहुत कठिन है और हमेशा कुछ अनिश्चितता है कि क्या आप कोड में कुछ स्थानों पर इस नियम से चिपकना भूल जाते हैं। अभी भी 1 मुझे गंदे और त्रुटि-प्रतीत होता है, मुझे लगता है कि एक प्रतिबंधित वातावरण में एक प्रक्रिया को मारने की कोशिश कर एक सुरक्षा त्रुटि उठा सकता है।

तो मैं सोच रहा है के बारे में एक और प्रॉक्सी ऑब्जेक्ट मॉडल जो एक्सेल ऑब्जेक्ट मॉडल की नकल करता बनाकर 2 सुलझाने (मेरे लिए, यह वस्तुओं मैं वास्तव में जरूरत है लागू करने के लिए पर्याप्त होगा)। सिद्धांत निम्नानुसार दिखेगा:

  • प्रत्येक एक्सेल इंटरऑप क्लास में इसकी प्रॉक्सी है जो उस वर्ग की ऑब्जेक्ट को लपेटती है।
  • प्रॉक्सी COM ऑब्जेक्ट को इसके अंतिम रूप में रिलीज़ करता है।
  • प्रॉक्सी इंटरऑप कक्षा के इंटरफ़ेस की नकल करता है।
  • मूल रूप से COM ऑब्जेक्ट लौटाए गए किसी भी तरीके को बदले में प्रॉक्सी वापस करने के लिए बदला जाता है। अन्य विधियां केवल आंतरिक COM ऑब्जेक्ट को कार्यान्वयन का प्रतिनिधित्व करती हैं।

उदाहरण:

public class Application 
{ 
    private Microsoft.Office.Interop.Excel.Application innerApplication 
     = new Microsoft.Office.Interop.Excel.Application innerApplication(); 

    ~Application() 
    { 
     Marshal.ReleaseCOMObject(innerApplication); 
     innerApplication = null; 
    } 

    public Workbooks Workbooks 
    { 
     get { return new Workbooks(innerApplication.Workbooks); } 
    } 
} 

public class Workbooks 
{ 
    private Microsoft.Office.Interop.Excel.Workbooks innerWorkbooks; 

    Workbooks(Microsoft.Office.Interop.Excel.Workbooks innerWorkbooks) 
    { 
     this.innerWorkbooks = innerWorkbooks; 
    } 

    ~Workbooks() 
    { 
     Marshal.ReleaseCOMObject(innerWorkbooks); 
     innerWorkbooks = null; 
    } 
} 

आप के लिए मेरे सवालों का विशेष रूप से कर रहे हैं:

  • कौन इस एक बुरा विचार पाता है और क्यों?
  • यह एक गहरा विचार कौन पाता है? यदि हां, तो किसी ने अभी तक ऐसे मॉडल को लागू/प्रकाशित क्यों नहीं किया है? क्या यह केवल प्रयास के कारण है, या क्या मुझे उस विचार के साथ एक हत्या की समस्या याद आ रही है?
  • क्या यह फाइनल में रिलीजकॉम ऑब्जेक्ट करने के लिए असंभव/खराब/त्रुटि-प्रवण है? (मैंने केवल इसे अंतिम रूप में एक निपटान() में डालने के प्रस्तावों को देखा है - क्यों?)
  • यदि दृष्टिकोण समझ में आता है, तो इसे सुधारने के लिए कोई सुझाव?

उत्तर

5

यह असंभव/बुरा/खतरनाक नाशक में ReleaseCOMObject क्या करना है? (मैंने केवल एक विनाशक के बजाय इसे एक निपटान() में रखने के प्रस्तावों को देखा है - क्यों?)

यह सलाह दी जाती है कि आप अपने क्लीनअप कोड को अंतिमकरण में न डालें क्योंकि सी ++ में विनाशक के विपरीत इसे निश्चित रूप से नहीं कहा जाता है। वस्तु के दायरे से बाहर होने के तुरंत बाद इसे बुलाया जा सकता है। इसमें एक घंटा लग सकता है। इसे कभी नहीं कहा जा सकता है। आम तौर पर यदि आप अप्रबंधित वस्तुओं का निपटान करना चाहते हैं तो आपको IDISposable पैटर्न का उपयोग करना चाहिए, न कि अंतिमकर्ता।

यह solution कि आपने कचरा कलेक्टर को स्पष्ट रूप से बुलाकर और अंतिमकर्ताओं को पूरा करने की प्रतीक्षा करके उस समस्या के आसपास काम करने के प्रयासों से जुड़ा हुआ है। यह वास्तव में सामान्य रूप से अनुशंसित नहीं है लेकिन इस विशेष स्थिति के लिए कुछ लोग इसे बनाए गए सभी अस्थायी अप्रबंधित वस्तुओं का ट्रैक रखने में कठिनाई के कारण स्वीकार्य समाधान मानते हैं। लेकिन स्पष्ट रूप से सफाई करना इसे करने का सही तरीका है। हालांकि ऐसा करने में कठिनाई दी गई, यह "हैक" स्वीकार्य हो सकता है। ध्यान दें कि यह समाधान शायद आपके द्वारा प्रस्तावित विचार से बेहतर है।

यदि आप इसके बजाय स्पष्ट रूप से साफ करने की कोशिश करना चाहते हैं, तो "COM ऑब्जेक्ट्स के साथ दो बिंदुओं का उपयोग न करें" दिशानिर्देश आपको आपके द्वारा बनाए गए प्रत्येक ऑब्जेक्ट का संदर्भ रखने में याद रखने में मदद करेगा ताकि आप उन्हें साफ़ कर सकें हो गया।

+0

आप मूलधन में finalizer साथ ठीक कह रहे हैं, लेकिन इस विशेष स्थिति में मैं कह सकते हैं: चलो कचरा कलेक्टर को ज़िम्मेदारी सौंपना है, के कारण के बाद से फाइनलइज़र मैं जीसी पर भरोसा कर सकता हूं जैसे ही ऑब्जेक्ट ऑब्जेक्ट नष्ट हो जाता है, COM COM ऑब्जेक्ट को भी जारी कर सकता है। अगर मैं कोड पर किसी स्थान पर सभी संसाधनों को स्पष्ट रूप से रिलीज़ करना चाहता हूं, तो मैं जीसी.कोलेक्ट() का उपयोग कर सकता हूं। – chiccodoro

+0

@chiccodoro: इस विधि के साथ समस्या यह है कि यह जीसी के कार्यान्वयन विवरण पर निर्भर है। यदि जीसी थोड़ा बदलता है तो यह अब काम नहीं कर सकता है। लेकिन मैं इस स्थिति में इसे ठीक से करने में कठिनाई को समझता हूं, और यह कि कुछ स्थितियों में हैक सबसे अधिक लागत प्रभावी समाधान हो सकता है। –

+0

हम्म। में तुम्हारी बात समझ रहा हूँ। लेकिन प्रत्येक एकल बिंदु के लिए एक उपयोग() का उपयोग करना कठिन है। हो सकता है कि एक्सेल पर केवल एक डिस्प्ले() विधि को परिभाषित करें। आवेदन जो जीसी.कोलेक्ट() चलाता है ताकि इस बिंदु पर अन्य सभी एक्सेल ऑब्जेक्ट भी जारी किए जा सकें? एक्सेल तक। आवेदन "उपयोग" दायरे को छोड़ देता है, मुझे अपने प्रोग्राम को COM संसाधनों को रिलीज़ करने की आवश्यकता नहीं होती है जो एप्लिकेशन से निकलती हैं। – chiccodoro

2

हम एमएसडीएन पत्रिका में वर्णित लाइफटाइमस्कोप कक्षा का उपयोग करते हैं। इसका उपयोग वस्तुओं को ठीक से साफ करता है और हमारे एक्सेल निर्यात के साथ बहुत अच्छा काम करता है। कोड यहाँ डाउनलोड किया जा सकता है और भी पत्रिका के एक लेख में शामिल हैं:

http://lifetimescope.codeplex.com/SourceControl/changeset/changes/1266

+0

हाय कोडेज़ी, दिलचस्प लिंक के लिए धन्यवाद। – chiccodoro

+0

कूल लिंकज़ धन्यवाद दोस्त। –

0

मुझे क्या करना चाहते हैं:

class ScopedCleanup<T> : IDisposable where T : class 
{ 
    readonly Action<T> cleanup; 

    public ScopedCleanup(T o, Action<T> cleanup) 
    { 
     this.Object = o; 
     this.cleanup = cleanup; 
    } 

    public T Object { get; private set; } 

    #region IDisposable Members 

    public void Dispose() 
    { 
     if (Object != null) 
     { 
      if(cleanup != null) 
       cleanup(Object); 
      Object = null; 
      GC.SuppressFinalize(this); 
     } 
    } 

    #endregion 

    ~ScopedCleanup() { Dispose(); } 
} 

static ScopedCleanup<T> CleanupObject<T>(T o, Action<T> cleanup) where T : class 
{ 
    return new ScopedCleanup<T>(o, cleanup); 
} 

static ScopedCleanup<ComType> CleanupComObject<ComType>(ComType comObject, Action<ComType> actionBeforeRelease) where ComType : class 
{ 
    return 
     CleanupObject(
      comObject, 
      o => 
      { 
       if(actionBeforeRelease != null) 
        actionBeforeRelease(o); 
       Marshal.ReleaseComObject(o); 
      } 
     ); 
} 

static ScopedCleanup<ComType> CleanupComObject<ComType>(ComType comObject) where ComType : class 
{ 
    return CleanupComObject(comObject, null); 
} 

प्रयोग मामला। बाहर निकलने के लिए कॉल, जो आवश्यक प्रतीत हो रहा है नोट प्रक्रिया अंत बनाने के लिए: अपने प्रोजेक्ट MS Office for .NET पर

using (var excel = CleanupComObject(new Excel.Application(), o => o.Quit())) 
using (var workbooks = CleanupComObject(excel.Object.Workbooks)) 
    { 
     ... 
    } 
+0

हाय रोटेरक। यह IDISposable दृष्टिकोण की एक दिलचस्प वृद्धि की तरह दिखता है, लेकिन यह मेरे प्रश्न का उत्तर नहीं देता है। (या फिर मुझे बिंदु याद आती है।) – chiccodoro

+1

जैसा कि उल्लेख किया गया है, IDISposable का उपयोग करने का तरीका अंतिम रूप में नहीं है। अंतिमकर्ता यह सुनिश्चित करेंगे कि संसाधन साफ़ हो गया है, लेकिन आपको कब पर नियंत्रण नहीं है। जीसी। चयन इस बात की गारंटी नहीं देता है कि सब कुछ तुरंत एकत्र किया जाएगा, इसलिए यह समाधान नहीं है। रिलीज होने पर एक डिस्पोजेबल आपको सख्त नियंत्रण देगा। इसके अलावा, उपयोग-कथन आपको इसे अपवाद-सुरक्षित तरीके से करने देता है। (बस याद रखें जब डिबगिंग आपके ऐप को क्लीनअप से पहले समय से पहले नहीं रोकती है, या यह नहीं किया जाएगा, और आप एक्सेल प्रक्रियाओं का एक गुच्छा चलाना समाप्त कर देंगे।) – Rotaerk

+0

ऑब्जेक्ट्स पर छोड़ा जाने वाला कारण यह है क्योंकि आप हैवेन्ट को कॉल करने के लिए कॉल के बीच .WaitForPendingFinalizers() कहा जाता है() यह इतना आसान है। –

1

देखो। मूल VB.NET देर से बाध्यकारी क्षमता के माध्यम से रेफरेंसिक रैपर ऑब्जेक्ट्स और देशी ऑब्जेक्ट्स के साथ हल समस्या है।

+0

हाय टीसीके। क्या आप उस पर विस्तार कर सकते हैं? प्रोजेक्ट पेज में आप लिखते हैं: "एमएस ऑफिस प्राथमिक इंटरऑप असेंबली की आवश्यकता नहीं है।" क्या इसका मतलब यह है कि किसी को अपने ऑब्जेक्ट मॉडल को सीधे संवाद करने की आवश्यकता नहीं है क्योंकि रैपर ऑब्जेक्ट्स का ख्याल रखना पड़ता है, या इसका मतलब यह है कि आपने बहुत कम स्तर के कार्यान्वयन किया है जो इंटरऑप असेंबली को पूरी तरह से बदल देता है? – chiccodoro

+0

हां, यह interopassembly के मानक तरीके काम करता है। यह रनटाइम पर COM ऑब्जेक्ट मॉडल गतिशीलता का निरीक्षण करता है। यह पीआईए से धीमा है लेकिन संस्करण (भविष्य संस्करण शामिल) से स्वतंत्र है। – TcKs

+0

यह वास्तविक दिलचस्प लगता है। - आपने 2008 में कोड और वेब पेज को आखिरी बार बदल दिया? – chiccodoro

0

क्या इसके लायक है के लिए, Excel Refresh Service on codeplex इस तर्क का उपयोग करता:

public static void UsingCOM<T>(T reference, Action<T> doThis) where T : class 
    { 
     if (reference == null) return; 
     try 
     { 
      doThis(reference); 
     } 
     finally 
     { 
      Marshal.ReleaseComObject(reference); 
     } 
    } 
+0

नोटिस के लिए धन्यवाद! इससे कई घोंसले कॉलबैक उत्पन्न होंगे, इस प्रकार मुझे उपयोग() दृष्टिकोण पर एक लाभ दिखाई नहीं देता है – chiccodoro

संबंधित मुद्दे