2009-07-28 8 views
5

मेरी कक्षा में इंटरऑप से एक ऑब्जेक्ट होता है और उस पर एक विधि कॉल करता है जो इसे सामान आवंटित करता है। यह भी है कि सामान को मुक्त करने के लिए एक विधि को उजागर करता है, तो मैं उम्मीद मैं निपटान() में इस फोन करना चाहिए:इंटरऑप COM ऑब्जेक्ट को लपेटते समय मैं C# में निपटान पैटर्न को कैसे कार्यान्वित करूं?

class MyClass : IDisposable 
{ 
    private DllName.ComClassName comInstance; 

    void SomeMethod() 
    { 
     comInstance = new DllName.ComClassName(); 
     comInstance.AllocStuff(); 
    } 

    public void Dispose() 
    { 
     comInstance.FreeThatStuff(); 
    } 
} 

अब, मैं वह सब का विस्तार करना चाहिए निपटान पैटर्न का पालन करने के लिए। मैं कोई अन्य डिस्पोजेबल या अप्रबंधित संसाधन जारी करने के लिए है, तो यह मानते हुए कि comInstance प्रबंधित किया जाता है (कि क्या इंटरॉप नहीं करता है, प्रबंधित में अप्रबंधित लपेटता?), मैं करने के लिए पैटर्न disolves लगता है:

public void Dispose() 
{ 
    if (comInstance != null) 
    { 
     comInstance.FreeStuff(); 
     comInstance = null; 
    } 
} 

कौन सा जब तक कि मैं लीक स्पष्ट रूप से MyClass के उदाहरणों पर निपटान() को कॉल करें, जो निपटान पैटर्न को त्रुटिपूर्ण कर देगा? तो इसका मतलब यह है comInstance अप्रबंधित होना चाहिए, और पैटर्न के लिए disolves:

public void Dispose() 
{ 
    DisposeComInstance(); 
    GC.SuppressFinalize(this); 
} 

~MyClass() 
{ 
    DisposeComInstance(); 
} 

private void DisposeComInstance() 
{ 
    if (comInstance != null) 
    { 
     comInstance.FreeStuff(); 
     comInstance = null; 
    } 
} 

संपादित करें:

  1. पूरा पैटर्न के साथ मेरी कक्षा को अव्यवस्थित बचने के लिए, मैं सिर्फ अपनी कक्षा को सील कर सकता है?
  2. मुझे कैसे पता चलेगा ComClassName (और सामान्य रूप से किसी भी वर्ग) अप्रबंधित है?

उत्तर

2

ऐसा लगता है कि आपको लगभग इसे खींचा गया है। मैं उस पैटर्न पर वापस आऊंगा जहां आपके पास एक संरक्षित आभासी डिस्पोजिंग है जो एक बुलियन पैरामीटर लेता है जो इंगित करता है कि प्रबंधित वस्तुओं का निपटान किया जाना चाहिए या नहीं। इस तरह कोई आपके पीछे आ रहा है implement IDisposable properly जारी रहेगा। क्यों, सबसे पहले Implementing IDisposable and the Dispose pattern properly.

+1

मेटा-टिप्पणी: सुनिश्चित करें कि आपका निपटान (बूल) पंक्ति में कई बार बुलाया जा सकता है। एक अपवाद को फेंकने की संभावना को कम करने की कोशिश करें (हमेशा संभव नहीं)। – user7116

+1

मेटा-मेटा टिप्पणी - साथ ही साथ, यह महत्वपूर्ण है कि आप कभी भी ताले हासिल न करें या अपने अप्रबंधित सफाई के दौरान लॉकिंग का उपयोग न करें। – womp

3

अंतत: आप पैटर्न के इस प्रकार चाहते हैं , लेकिन इसे स्पष्ट रूप से myClass को कॉल करके बुलाए जाने से बचने का प्रयास करें। प्रदर्शन करें या 'उपयोग' के माध्यम से।

उदा।

var myClass = new MyClass() 
try 
{ 
    //do stuff 
} 
finally 
{ 
    myClass.Dispose(); 
} 

या

using (var myClass = new MyClass()) 
{ 
    //do stuff 
} 

Marshall.ReleaseComObject

आप COM ऑब्जेक्ट के बहुत सारे का उपयोग कर रहे हैं, तो मैं आपको यह भी Mashall.ReleaseComObject (comObj) का उपयोग स्पष्ट रूप से के लिए संदर्भ को साफ करने के लिए सुझाव आरसीडब्ल्यू

तो, इस तरह कोड कहीं और सुझाव दिया:

if (comInstance != null) 
{ 
    comInstance.FreeStuff(); 
    comInstance = null; 
} 

बन जाएगा:

if (comInstance != null) 
{ 
    comInstance.FreeStuff(); 

    int count = Marshall.ReleaseComObject(comInstance); 
    if (count != 0) 
    { 
      Debug.Assert(false, "comInstance count = " + count); 
      Marshal.FinalReleaseComObject(comInstance); 
    } 

    comInstance = null; 
} 

ReleaseComObject (की वापसी मान की जाँच के दौरान) सख्ती से आवश्यक नहीं है, मैं करने के लिए यह जांच करना चाहते सुनिश्चित करें कि अपेक्षित के रूप में चीजों को बढ़ाया/घटाया जा रहा है।

2-डॉट नियम

आप इस का उपयोग करने का निर्णय लेते हैं, कुछ के बारे में पता होना करने के लिए है कि कुछ कोड को ठीक से अपने COM ऑब्जेक्ट जारी करने के लिए पुनर्संशोधित की जरूरत हो सकती है। एक विशेष रूप से मैं 2-डॉट नियम कहता हूं। COM ऑब्जेक्ट्स का उपयोग करने वाली कोई भी पंक्ति जिसमें 2 बिंदुओं को नज़दीकी ध्यान देने की आवश्यकता होती है। उदाहरण के लिए,

var name = myComObject.Address.Name; 

इस बयान में हम पता COM ऑब्जेक्ट को उसके RCW संदर्भ गिनती बढ़ाने के लिए एक संदर्भ मिलता है, लेकिन हम ReleaseComObject कॉल करने के लिए एक अवसर की जरूरत नहीं है। ऐसा करने के लिए इसे तोड़ने के लिए नीचे होगा एक बेहतर तरीका (try..finally स्पष्टता के लिए छोड़े गए):

var address = myComObject.Address; 
var name = address.Name; 
MyReleaseComObject(address); 

जहां MyReleaseComObject मेरी गिनती की जांच और FinalReleaseComObject() ऊपर से लपेटकर एक उपयोगिता विधि है।

+0

-1, आपको अप्रबंधित वस्तुओं को if (disposing) ब्लॉक के बाहर स्थानांतरित करने की आवश्यकता है। अप्रबंधित हमेशा साफ किया जाना चाहिए। – user7116

+0

गह! आप सही हैं, मैंने इसे अपने कुछ कोड से कॉपी किया है जो उन घटकों का उपयोग कर रहे थे जिनके पास अप्रबंधित कोड था लेकिन ओपी के उदाहरण में संपादित किया गया था और संपादित किया गया था ... हार के लिए पेस्ट करें। फिक्स्ड। – womp

+0

+1, सही ढंग से कार्यान्वित ;- डी – user7116

3

की जाँच

public void Dispose() 
{ 
    Dispose(true); 
    GC.SuppressFinalize(this); 
} 

~MyClass() 
{ 
    Dispose(false); 
} 

private void Dispose(bool disposing) 
{ 
    if (disposing) 
    { 
     // Dispose of disposable objects here 

    } 

    // Other unmanaged cleanup here which will be called by the finalizer 
    if (comInstance != null) 
    { 
     comInstance.FreeStuff(); 
     comInstance = null; 
    } 

    // Call base dispose if inheriting from IDisposable class. 
    base.Dispose(true); 
} 

पर एक बड़ा लेख के लिए, मैं उन है कि एक बैकअप के रूप में एक finalizer होने का सुझाव से सहमत:

public void Dispose() 
{ 
    this.Dispose(true); 
    GC.SuppressFinalize(this); 
} 

~MyClass() 
{ 
    this.Dispose(false); 
} 

protected virtual void Dispose(bool disposing) 
{ 
    // if (disposing) 
    // { 
    //  // Managed 
    // } 

    if (comInstance != null) 
    { 
     comInstance.FreeStuff(); 
     comInstance = null; 
    } 

    // base.Dispose(disposing) if required 
} 
संबंधित मुद्दे