2010-05-28 17 views
27

संपादित करेंक्या * हर * एक्सेल इंटरऑप ऑब्जेक्ट को मार्शल का उपयोग करके रिलीज़ करने की आवश्यकता है। ReleaseComObject?

कृपया How do I properly clean up Excel interop objects? भी देखें। मैं हाल ही में इस सवाल में आया, और यह COM वस्तुओं का सही तरीके से निपटान करने की समस्या में बहुत अंतर्दृष्टि प्रदान करता है। निश्चित रूप से पहले (चिह्नित) जवाब परे की जाँच करें, क्योंकि अन्य उत्तर सरल सलाह "दो डॉट्स का उपयोग नहीं करते हैं" और "हर कॉम वस्तु के लिए ReleaseComObject का उपयोग करें" से परे जाना।

मैं पहली जगह में इस सवाल पर दोबारा गौर किया क्योंकि मैंने महसूस किया कि, दर्ज की और मेरे सभी COM ऑब्जेक्ट निपटाने के बारे में बहुत ही गहन होने के बावजूद मेरी एक्सेल उदाहरणों अभी भी ठीक से निपटारा नहीं किया जा रहा था। यह पता चला है कि COM ऑब्जेक्ट्स को बनाया जा सकता है जो पूरी तरह से स्पष्ट नहीं हैं (यानी, आप COM ऑब्जेक्ट्स को याद कर सकते हैं भले ही आप दो बिंदुओं का उपयोग न करें)। इसके अलावा, भले ही आप पूरी तरह से हों, यदि आपकी परियोजना एक निश्चित आकार से आगे बढ़ती है, तो COM ऑब्जेक्ट खोने का मौका 100% तक पहुंच जाता है। और जब ऐसा होता है तो उसे याद करने में बहुत मुश्किल हो सकती है। उपरोक्त लिंक किए गए प्रश्न का उत्तर यह सुनिश्चित करने के लिए कुछ अन्य तकनीक प्रदान करता है कि एक्सेल इंस्टेंस निश्चित रूप से बंद हो जाता है। इस बीच, मैंने ऊपर दिए गए प्रश्न से जो कुछ सीखा है उसे प्रतिबिंबित करने के लिए मैंने अपने ComObjectManager (नीचे) में एक छोटा (लेकिन महत्वपूर्ण) अपडेट किया है।

मूल प्रश्न

मैं कई उदाहरण हैं, जहां Marshal.ReleaseComObject() एक्सेल इंटरॉप वस्तुओं (यानी, नाम स्थान Microsoft.Office.Interop.Excel से वस्तुओं) के साथ प्रयोग किया जाता है देखा है, लेकिन मैंने देखा है यह विभिन्न के लिए इस्तेमाल किया डिग्री कम है।

मैं सोच रहा हूँ अगर मैं कुछ इस तरह से प्राप्त कर सकते हैं:

var application = new ApplicationClass(); 
try 
{ 
    // do work with application, workbooks, worksheets, cells, etc. 
} 
finally 
{ 
    Marashal.ReleaseComObject(application) 
} 

या मैं इस विधि में के रूप में हर एक वस्तु बनाई रिलीज करने के लिए, की जरूरत है:

public void CreateExcelWorkbookWithSingleSheet() 
{ 
    var application = new ApplicationClass(); 
    var workbook = application.Workbooks.Add(_missing); 
    var worksheets = workbook.Worksheets; 
    for (var worksheetIndex = 1; worksheetIndex < worksheets.Count; worksheetIndex++) 
    { 
     var worksheet = (WorksheetClass)worksheets[worksheetIndex]; 
     worksheet.Delete(); 
     Marshal.ReleaseComObject(worksheet); 
    } 
    workbook.SaveAs(
     WorkbookPath, _missing, _missing, _missing, _missing, _missing, 
     XlSaveAsAccessMode.xlExclusive, _missing, _missing, _missing, _missing, _missing); 
    workbook.Close(true, _missing, _missing); 
    application.Quit(); 
    Marshal.ReleaseComObject(worksheets); 
    Marshal.ReleaseComObject(workbook); 
    Marshal.ReleaseComObject(application); 
} 

क्या संकेत मिले, मुझे यह सवाल पूछना है कि, मैं LINQ भक्त होने के नाते, मैं वास्तव में ऐसा कुछ करना चाहता हूं:

var worksheetNames = worksheets.Cast<Worksheet>().Select(ws => ws.Name); 

... लेकिन मुझे चिंता है कि अगर मैं प्रत्येक वर्कशीट (ws) ऑब्जेक्ट को जारी नहीं करता हूं तो मैं मेमोरी लीक या भूत प्रक्रियाओं के साथ समाप्त हो जाऊंगा।

किसी भी अंतर्दृष्टि इस पर सराहना की जाएगी।

अद्यतन

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

public class ComObjectManager : IDisposable 
{ 
    private Stack<object> _comObjects = new Stack<object>(); 

    public TComObject Get<TComObject>(Func<TComObject> getter) 
    { 
     var comObject = getter(); 
     _comObjects.Push(comObject); 
     return comObject; 
    } 

    public void Dispose() 
    { 
     // these two lines of code will dispose of any unreferenced COM objects 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 

     while (_comObjects.Count > 0) 
      Marshal.ReleaseComObject(_comObjects.Pop()); 
    } 
} 

यहाँ एक उपयोग उदाहरण है:

public void CreateExcelWorkbookWithSingleSheet() 
{ 
    using (var com = new ComObjectManager()) 
    { 
     var application = com.Get<ApplicationClass>(() => new ApplicationClass()); 
     var workbook = com.Get<Workbook>(() => application.Workbooks.Add(_missing)); 
     var worksheets = com.Get<Sheets>(() => workbook.Worksheets); 
     for (var worksheetIndex = 1; worksheetIndex < worksheets.Count; worksheetIndex++) 
     { 
      var worksheet = com.Get<WorksheetClass>(() => (WorksheetClass)worksheets[worksheetIndex]); 
      worksheet.Delete(); 
     } 
     workbook.SaveAs(
      WorkbookPath, _missing, _missing, _missing, _missing, _missing, 
      XlSaveAsAccessMode.xlExclusive, _missing, _missing, _missing, _missing, _missing); 
     workbook.Close(true, _missing, _missing); 
     application.Quit(); 
    } 
} 
+0

+1 ComObjectManager क्लास के लिए +1 जो वस्तुओं को जारी करने का ख्याल रखता है। –

+0

हालांकि, ComObjectManager के आपके समाधान के परिणामस्वरूप संकलक द्वारा पृष्ठभूमि में बनाई गई कई अज्ञात विधि के कारण असेंबली के आकार में वृद्धि हो सकती है। –

+0

प्रबंधक के साथ अच्छा विचार। –

उत्तर

13

मेरा मानना ​​है कि आप प्रत्येक COM वस्तु पर ReleaseComObject फोन करना होगा।चूंकि वे कचरे से एकत्र नहीं होते हैं, इसलिए अभिभावक-बाल पदानुक्रम वास्तव में समीकरण में नहीं आता है: भले ही आप मूल वस्तु को छोड़ दें, यह किसी भी बच्चे की वस्तुओं पर संदर्भ गणना को कम नहीं करता है।

+0

बस कुछ के बारे में सोचा ... क्या यह एक्सेल इंटरऑप फ़ंक्शंस पर भी लागू होता है जो मूल्य प्रकार लौटाता है? उदाहरण के लिए 'myCell.get_Address()' एक 'स्ट्रिंग' देता है। 'myColumn.AutoFit() '' bool' देता है। क्या मुझे लगता है कि ये कोई समस्या नहीं है? – devuxer

+4

हां, आप मान सकते हैं कि वे कोई समस्या नहीं हैं। आपको केवल COM ऑब्जेक्ट्स को स्पष्ट रूप से रिलीज़ करने की आवश्यकता है; मानक .NET प्रकार ठीक हैं। (आपके रैपर बीटीडब्ल्यू, सुंदर सुरुचिपूर्ण समाधान पर अच्छा काम।) –

+0

धन्यवाद और धन्यवाद! :) – devuxer

6

आपको मार्शल को कॉल करना चाहिए। कृपया अपने मुख्य कोड ऑब्जेक्ट पर न केवल आपके कोड में उपयोग की जाने वाली प्रत्येक COM ऑब्जेक्ट पर ReleleaseComObject।

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