चूंकि आप इस निर्माण का उपयोग बहु-थ्रेडेड एप्लिकेशन में करना चाहते हैं और उसी उदाहरण को थ्रेड (जैसे आप अपनी टिप्पणी में उल्लिखित करते हैं) का पुन: उपयोग करना चाहते हैं, तो आप अपने डी कंटेनर को कॉन्फ़िगर करके इस समस्या को हल करने में सक्षम नहीं होंगे।
आप दौड़ की स्थिति के कारण निपटान के बाद ऑब्जेक्ट को नवीनीकृत करने के लिए कॉन्फ़िगर नहीं कर सकते हैं। निम्नलिखित परिदृश्य की कल्पना करें:
- थ्रेड 1 कंटेनर से एक उदाहरण का अनुरोध करता है।
- यह पहला अनुरोध है और कंटेनर एक नया उदाहरण बनाएगा।
- थ्रेड 2 कंटेनर उदाहरण चरण में बनाए गए 2.
- थ्रेड 1 उदाहरण के साथ किया और
Dispose
कॉल रिटर्न कंटेनर
- से एक उदाहरण अनुरोध करता है।
- थ्रेड 2 उदाहरण का उपयोग शुरू करता है, लेकिन उदाहरण का निपटारा किया जाता है, और अपवाद फेंकता है।
समस्या यह है कि एप्लिकेशन को एक उदाहरण का संदर्भ मिलेगा जिसे निपटान किया जा सकता है।
यदि आप कर सकते हैं तो अपने आवेदन को फिर से डिजाइन करके इसे करने से रोकने का प्रयास करें। IDisposable
को लागू करने वाले सेवा प्रकारों का पर्दाफाश करना एक बुरा अभ्यास है, क्योंकि IDisposable
एक रिसाव अमूर्त है। IDisposable
को लागू करने के लिए इन सेवाओं के किसी भी कार्यान्वयन को रोकने के लिए भी मेरी व्यक्तिगत वरीयता है। ज्यादातर परिदृश्यों में एक नया स्वरूप आपको ऐसा करने से रोक सकता है।
यदि आपको IDisposable
ऑब्जेक्ट्स का उपयोग करने की आवश्यकता है, तो ऐसा करने का सामान्य तरीका इन IDisposable
ऑब्जेक्ट्स बनाने वाली फैक्ट्रियों को बनाना और इंजेक्ट करना है। इस तरह उपभोक्ता किसी भी समस्या के बिना सुरक्षित रूप से ऐसी वस्तु का निपटान कर सकता है।
सामान्य समस्या यह है कि IDisposable
लागू करने वाली वस्तुओं को बनाना मुश्किल है, जो वास्तव में थ्रेड-सुरक्षित हैं।
यदि आप वास्तव में यह चाहते हैं, तो आप एक सजावट बनाने की कोशिश कर सकते हैं जो संदर्भ गणना करता है। नीचे सजावट पर उदाहरण के लिए देखो। यह IService
लपेटता है और IService
लागू करता है। IService
लागू IDisposable
। सजावटी Func<IService
> प्रतिनिधि जो उदाहरणों के निर्माण की अनुमति देता है। वस्तुओं का निर्माण और निपटान lock
कथन द्वारा संरक्षित है और सजावटी कॉलर्स द्वारा संदर्भों की गणना करता है। अंतिम उपभोक्ता सजावट का निपटारा करने के बाद, यह ऑब्जेक्ट का निपटान करेगा और एक नया निर्माण करेगा।
public class ScopedServiceDecorator : IService
{
private readonly object locker = new object();
private Func<IService> factory;
private IService currentInstance;
private int referenceCount;
public ScopedServiceDecorator(Func<IService> factory)
{
this.factory = factory;
}
public void SomeOperation()
{
IService instance;
lock (this.locker)
{
instance = this.GetInstance();
this.referenceCount++;
}
instance.SomeOperation();
}
public void Dispose()
{
IService instance = null;
lock (this.locker)
{
this.referenceCount--;
if (this.referenceCount == 0)
{
instance = this.wrappedService;
this.wrappedService = null;
}
}
// Dispose the object outside the lock for performance.
if (instance != null)
{
instance.Dispose();
}
}
private IService GetInstance()
{
if (this.wrappedService == null)
{
this.wrappedService = this.factory();
}
return this.wrappedService;
}
}
कृपया ध्यान दें कि इस कार्यान्वयन अभी भी त्रुटिपूर्ण है, ऐसा निम्न कारणों से:
- कॉलिंग
Dispose
कई बार डेकोरेटर टूट जाता है।
- जब उपभोक्ता
SomeOperation
कई बार कॉल करते हैं (या IService
में कई विधियां हैं) कार्यान्वयन टूट जाएगा।
एक सजावट बनाने वाला बहुत कठिन है जो अपेक्षित कार्य करता है। ऐसा करने का एक आसान तरीका ऑब्जेक्ट तक पहुंच को क्रमबद्ध करना है, लेकिन जब आप ऐसा करते हैं, तो संभवतः आप प्रति थ्रेड के एक उदाहरण का उपयोग करना चाहते हैं। यह बहुत आसान होगा।
मुझे उम्मीद है कि इससे मदद मिलती है।
आप किस प्रकार का आवेदन चला रहे हैं? क्या यह एक बहु थ्रेडेड एप्लीकेशन है? – Steven
हां। उदाहरण प्रति थ्रेड की तरह कुछ उपयोगी नहीं होगा। – anthony