2009-06-04 16 views
12

COM ऑब्जेक्ट्स में आमतौर पर निर्धारक विनाश होता है: अंतिम संदर्भ जारी होने पर उन्हें मुक्त किया जाता है।सी # + COM इंटरऑप, निर्धारिती रिलीज

यह सी # - COM इंटरऑप में कैसे संभाला जाता है? कक्षाएं IDisposable लागू नहीं करती हैं, इसलिए मुझे एक स्पष्ट IU अज्ञात :: रिलीज़ को ट्रिगर करने का कोई तरीका नहीं दिखता है।

एक आकस्मिक परीक्षण से पता चलता है कि असुरक्षित COM ऑब्जेक्ट्स आलसी एकत्रित हो जाते हैं (यानी कचरा कलेक्टर रिलीज को ट्रिगर कर रहा है)। ओसीएम ऑब्जेक्ट्स के लिए मुझे क्या करना चाहिए जिसे अपग्रेड करने की आवश्यकता है? (उदाहरण के लिए बड़े या साझा महत्वपूर्ण संसाधनों को पकड़ना)?

मूल समस्या: हमारे पास एक COM लाइब्रेरी का उपयोग करके सी # अनुप्रयोग भारी है, और यह पागल की तरह लीक हो रहा है। ऐसा लगता है कि समस्याएं सी ++ और सी # कोड "के बीच" हैं (हमारे पास दोनों तक पहुंच है), लेकिन हम इसे कम नहीं कर सकते हैं।

उत्तर

16

आप सिस्टम का उपयोग कर COM इंटरऑप संदर्भों में हेरफेर कर सकते हैं। Runtime.InteropServices.Marshal क्लास। विशेष रूप से आप Marshal.ReleaseComObject पर एक नज़र रखना चाहते हैं।

+2

+1, क्योंकि इस बचाया मेरी जिंदगी एक बार से अधिक: एक एकल रिलीज की इजाजत दी -

यहाँ एक विकल्प Expression पेड़ का उपयोग करता है हमारे इरादे चर्चा करने के लिए, प्रत्येक नोड में मूल्य पर कब्जा है। – OregonGhost

5

हमें इससे काफी नुकसान हुआ है। नेट रनटाइम में बहुत से इंटरऑप संदर्भ लोड करने का प्रयास करना सबसे अच्छा नहीं है। साथ ही, यदि आप तुरंत कुछ जारी करने की आवश्यकता है तो आप Marshal.ReleaseComObject एपीआई का उपयोग कर सकते हैं।

एक और अच्छी विधि इंटरऑप कोड के चारों ओर टाइपएफ़ रैपर का उपयोग करने के लिए अपने क्लाइंट कोड को दोबारा करने के लिए है - यदि आपके पास प्रत्येक कोड में प्रत्येक कोड आरसीडब्ल्यू के लिए एक ज्ञात संदर्भ है, तो यह संभावना बढ़ जाती है कि इंटरऑप संदर्भ जीसीड किया जाएगा एक समय पर फैशन।

foo.bar.quux.xyzzy.groo(); // where foo, bar, quux and xyzzy are all COM references 

उपरोक्त कोड में डॉट्स के बीच वस्तुओं में से प्रत्येक को प्रभावी ढंग से लीक कर रहा है (शायद नहीं वास्तव में लंबे समय में) एक हम हैं के बाद से: मुख्य समस्या यह से बचना चाहता है "भी कई डॉट्स" में से एक है उदाहरण के लिए अंतर्निहित संदर्भ।

Foo foo; 
Bar bar=foo.bar; 
Quux quux=bar.quux; 
Xyzzy xyzzy=quux.xyzzy; 
xyzzy.groo(); 

अब संभवतः क्रम का उपयोग संदर्भ रिलीज करने के लिए:

ReleaseComObject(xyzzy); // etc... 
2

यह वह जगह है आपको उन्हें साफ करने के लिए एक अच्छा मौका है करने के उदाहरणों में से प्रत्येक के लिए नामित किया गया संदर्भ बनाने की आवश्यकता होगी related (but subtly different) question से, लेकिन मुझे लगता है कि जवाब बहुत साफ है - इसलिए मैंने सोचा कि यह यहां भी जोड़ रहा है।

static class ComExample { 
    static void Main() 
    { 
     using (var wrapper = new ReleaseWrapper()) 
     { 
      var baz = wrapper.Add(() => new Foo().Bar.Baz); 
      Console.WriteLine(baz.Name); 
     } 
    } 
} 
class ReleaseWrapper : IDisposable 
{ 
    List<object> objects = new List<object>(); 
    public T Add<T>(Expression<Func<T>> func) 
    { 
     return (T)Walk(func.Body); 
    } 
    object Walk(Expression expr) 
    { 
     object obj = WalkImpl(expr); 
     if (obj != null && Marshal.IsComObject(obj) 
       && !objects.Contains(obj)) { objects.Add(obj); } 
     return obj; 
    } 
    object WalkImpl(Expression expr) 
    { 
     switch (expr.NodeType) 
     { 
      case ExpressionType.Constant: 
       return ((ConstantExpression)expr).Value; 
      case ExpressionType.New: 
       NewExpression ne = (NewExpression)expr; 
       object[] args = ne.Arguments.Select(arg => Walk(arg)).ToArray(); 
       return ne.Constructor.Invoke(args); 
      case ExpressionType.MemberAccess: 
       MemberExpression me = (MemberExpression)expr; 
       object target = Walk(me.Expression); 
       switch (me.Member.MemberType) 
       { 
        case MemberTypes.Field: 
         return ((FieldInfo)me.Member).GetValue(target); 
        case MemberTypes.Property: 
         return ((PropertyInfo)me.Member).GetValue(target, null); 
        default: 
         throw new NotSupportedException(); 

       } 
      default: 
       throw new NotSupportedException(); 
     } 
    } 
    public void Dispose() 
    { 
     foreach(object obj in objects) { 
      Marshal.ReleaseComObject(obj); 
      Debug.WriteLine("Released: " + obj); 
     } 
     objects.Clear(); 
    } 
} 
संबंधित मुद्दे