2013-08-07 13 views
6

सुविधा और सुरक्षा कारणों से मैं से/एक पूलऑब्जेक्ट का उपयोग करने के लिए स्कोप हैंडलिंग के लिए उपयोग और निपटान() का दुरुपयोग?

public class Resource : IDisposable 
{ 
    public void Dispose() 
    { 
     ResourcePool.ReleaseResource(this); 
    } 
} 

public class ResourcePool 
{ 
    static Stack<Resource> pool = new Stack<Resource>(); 

    public static Resource GetResource() 
    { 
     return pool.Pop(); 
    } 

    public static void ReleaseResource(Resource r) 
    { 
     pool.Push(r); 
    } 
} 

और उपयोग की तरह

using (Resource r = ResourcePool.GetResource()) 
{ 
    r.DoSomething(); 
} 

पूल मैं कुछ पाया करने के लिए आवंटन और वस्तुओं की रिहाई के लिए using बयान उपयोग करना चाहते हैं स्कोप हैंडलिंग के लिए using और Dispose() का दुरुपयोग करने पर विषय, लेकिन उनमें से सभी using (Blah b = _NEW_ Blah()) शामिल करते हैं।
यहां वस्तुओं को उपयोग करने के दायरे को छोड़ने के बाद मुक्त नहीं किया जाना चाहिए बल्कि पूल में रखा जाना चाहिए।
यदि उपयोग कथन बस एक सादा try finally Dispose() तक फैलता है तो यह ठीक काम करना चाहिए, लेकिन दृश्यों के पीछे कुछ और हो रहा है या भविष्य में यह काम नहीं करेगा। नेट संस्करण?

+0

कॉलिंग निपटान() * हमेशा * वैकल्पिक है। क्या होगा जब क्लाइंट प्रोग्राम इसे कॉल नहीं करता है? देखना मुश्किल है कि कुछ "खराब" नहीं होता है। फाइनलाइज़र निपटान() का उपयोग नहीं किया जा रहा है, किसी भी तरह से आप Finalizer में रिलीज रिसोर्स() को कॉल नहीं कर सकते हैं। –

उत्तर

7

यह कोई दुर्व्यवहार नहीं है - यह सी # का एक सामान्य दायरा-संचालन मुहावरे है। उदाहरण के लिए, ADO.NET वस्तुओं (कनेक्शन, बयान, क्वेरी परिणाम) सामान्यतः using ब्लॉक में बंद होते हैं, भले ही इन वस्तुओं में से कुछ अपने Dispose तरीकों के अंदर उनके पूल के लिए वापस जारी किया गया हो:

using (var conn = new SqlConnection(dbConnectionString)) { 
    // conn is visible inside this scope 
    ... 
} // conn gets released back to its connection pool 
+0

यदि आप जानबूझकर संसाधनों के साथ इसका उपयोग कर रहे हैं तो यह पूरी तरह अपमानजनक है। – Firoso

2

IDisposable का उपयोग करने का यह एक वैध तरीका है। एक using बयान में एक DBConnection वस्तु लपेटकर कनेक्शन बंद सुनिश्चित करने के लिए और कनेक्शन पूल में लौट आता है -

वास्तव में, यह कैसे कनेक्शन पूलिंग भी .NET में किया जाता है।

निपटान विधि के लिए एक कॉल लेन-देन गुंजाइश की समाप्ति का सूचक:

TransactionScope एक वर्ग अन-लेन-देन को रोलबैक करने के लिए Dispose पैटर्न का उपयोग करता है के लिए एक और उदाहरण है।

2

हैं स्टेटमेंट का उपयोग करके बस एक सादा प्रयास में फैलता है अंततः निपटान() यह ठीक काम करना चाहिए, लेकिन दृश्यों के पीछे कुछ और हो रहा है या भविष्य में यह काम नहीं करेगा। नेट संस्करण?

ऐसा करता है। आपके कोड को ठीक काम करना चाहिए, और उसी तरह काम करने के लिए spec द्वारा गारंटी दी जाती है। वास्तव में, यह काफी आम है (एक अच्छे उदाहरण के लिए एसक्यूएल में कनेक्शन पूलिंग देखें।)

लिखित रूप में आपके कोड के साथ मुख्य समस्या यह है कि आप को using के भीतर स्पष्ट रूप से कॉल कर सकते हैं, पूल का कारण बन सकता है रिसोर्स को एक से अधिक बार धकेलने के लिए, क्योंकि यह सार्वजनिक एपीआई का हिस्सा है।

1

using कथन की आपकी समझ सही है (try, finally, Dispose)। मैं जल्द ही इस बदलाव को पहले से नहीं देखता हूं। अगर ऐसा होता तो इतनी सारी चीज़ें टूट जाएंगी।

आपके द्वारा नियोजित योजना के साथ कुछ भी गलत नहीं है। मैंने पहले इस तरह की चीज देखी है, जहां Dispose वास्तव में वस्तु को बंद नहीं करता है, बल्कि इसे किसी प्रकार के राज्य में रखता है जो "पूरी तरह से परिचालित नहीं है।"

आप बिल्कुल इस बारे में चिंतित हैं, तो आप इस तरह से है कि यह सामान्य Dispose कार्यान्वयन पैटर्न का पालन करता है में यह लागू कर सकते हैं। बस एक आवरण वर्ग कि IDisposable लागू करता है और अंतर्निहित वर्ग के सभी तरीकों को उजागर करता है। जब रैपर का निपटारा किया जाता है, तो अंतर्निहित वस्तु को पूल में रखें, रैपर नहीं। फिर आप रैपर को बंद कर सकते हैं, हालांकि यह चीज लपेटती है।

2

यह IDisposable और एक गरीब के दुरुपयोग की तरह दिखता है मेरे लिए डिजाइन निर्णय। सबसे पहले, यह पूल के बारे में जानने के लिए पूल में संग्रहीत वस्तुओं को मजबूर करता है। यह एक सूची प्रकार बनाने जैसा है जो किसी विशेष इंटरफ़ेस को लागू करने या कुछ कणों से प्राप्त करने के लिए वस्तुओं को मजबूर करता है आर कक्षा एक लिंक्डलिस्ट क्लास की तरह जो डेटा आइटम्स को Next और Previous पॉइंटर्स को शामिल करने के लिए मजबूर करता है जो सूची का उपयोग कर सकते हैं।

इसके अतिरिक्त, आपके पास पूल आपके लिए संसाधन आवंटित करता है, लेकिन फिर संसाधन को पूल में वापस रखने का आह्वान होता है। ऐसा लगता है ... विषम।

मुझे लगता है कि एक बेहतर विकल्प होगा:

var resource = ResourcePool.GetResource(); 
try 
{ 
} 
finally 
{ 
    ResourcePool.FreeResource(resource); 
} 

यह थोड़ा और अधिक कोड (कोशिश/अंत में बल्कि using की तुलना में), लेकिन एक क्लीनर डिजाइन है। यह निहित वस्तुओं को कंटेनर के बारे में जानने से राहत देता है, और यह स्पष्ट रूप से दिखाता है कि पूल वस्तु का प्रबंधन कर रहा है।

+0

यदि मैं सार्वजनिक पुस्तकालय के लिए कोड था तो मैं आपके साथ सहमत होगा। – FrankU

+0

यदि मैं सार्वजनिक पूल लाइब्रेरी के लिए कोड था तो मैं आपके साथ सहमत होगा। लेकिन चूंकि यह एक विशिष्ट अनुप्रयोग/उद्देश्य के लिए है और वास्तविक संसाधन और पूल कक्षाएं बहुत निकटता से जुड़ी हैं, इसलिए मैं इसे एक मुद्दा नहीं मानता और सिंटैक्स का उपयोग करके संक्षिप्त की तरह नहीं मानता। – FrankU

0

आप क्या कर रहे हैं सी ++ और आरएआईआई की तरह है। और सी # में, यह करीब है कि सी ++/आरएआईआई मुहावरे जैसा आप प्राप्त कर सकते हैं।

एरिक लिपर्ट, जो सी # के बारे में एक चीज़ या दो को जानता है, आईडीआईएस का उपयोग करने और सी # आरएआईआई मुहावरे के रूप में कथन का उपयोग करने के खिलाफ है। यहां उसकी गहराई से प्रतिक्रिया देखें, Is it abusive to use IDisposable and "using" as a means for getting "scoped behavior" for exception safety?

इस आरएआईआई फैशन में उपयोग किए जाने वाले आईडीस्पोजेबल के साथ समस्या का एक हिस्सा यह है कि IDisposable में सही तरीके से उपयोग करने के लिए बहुत कठोर आवश्यकताएं हैं। लगभग सभी सी # कोड मैंने देखा है कि IDISposable का उपयोग पैटर्न को सही ढंग से कार्यान्वित करने में विफल रहता है। जो डफी ने एक ब्लॉग पोस्ट किया है जो IDISposable पैटर्न http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/ को लागू करने के उचित तरीके के बारे में सावधानीपूर्वक विस्तार में जाता है। जो की जानकारी एमएसडीएन पर उल्लिखित की तुलना में अधिक विस्तृत और व्यापक है। जो सी # के बारे में कुछ भी जानता है, और वहां बहुत सारे स्मार्ट योगदानकर्ता थे जिन्होंने उस दस्तावेज़ को दूर करने में मदद की।

बेयर-हड्डियों-न्यूनतम आईडीस्पोजेबल पैटर्न (आरएआईआई जैसे उपयोग के लिए) जैसे वर्ग को सील करने के लिए सरल चीजें की जा सकती हैं, और चूंकि कोई अप्रबंधित संसाधन नहीं है, जिसमें फाइनेंजर नहीं है, और ऐसे में। एमएसडीएन https://msdn.microsoft.com/en-us/library/system.objectdisposedexception%28v=vs.110%29.aspx एक अच्छा अवलोकन है, लेकिन जो की जानकारी में सभी गौरी विवरण हैं।

लेकिन एक चीज जिसे आप आईडीस्पोजेबल से दूर नहीं ले सकते हैं, इसकी "वायरल" प्रकृति है। जिन वर्गों को एक ऐसे सदस्य पर रखा जाता है जो स्वयं को पहचानने योग्य है, उसे IDIS39able योग्य होना चाहिए ... using(RAII raii = Pool.GetRAII()) परिदृश्य में कोई समस्या नहीं है, लेकिन कुछ के बारे में बहुत सावधान रहना चाहिए।

एरिक की स्थिति के बावजूद, जो कि मैं अन्य सभी चीज़ों पर उससे सहमत हूं) और जो के 50 पृष्ठ निबंध IDISposable पैटर्न को सही ढंग से कार्यान्वित करने के तरीके के बारे में कहा जा रहा है ... मैं इसे सी #/RAII idiom खुद।

अब केवल अगर सी # था 1) गैर-शून्य संदर्भ (जैसे सी ++ या डी या स्पेक #) और 2) गहराई से अपरिवर्तनीय डेटा प्रकार (जैसे डी, या यहां तक ​​कि एफ # [ आप एफ # प्रकार में अपरिवर्तनीय सी # , लेकिन यह बॉयलरप्लेट का एक बहुत सी है, और यह सही पाने के लिए बहुत मुश्किल है ...आसान हार्ड, और हार्ड असंभव]) और 3) भाषा के हिस्से के रूप में डिज़ाइन-बाय-कॉन्ट्रैक्ट (जैसे डी या एफिल या स्पेक #, सी # कोड अनुबंध घृणा की तरह नहीं) बनाता है। श्वास शायद सी # 7.

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