2012-05-05 14 views
18

में स्थिर रचनाकारों के साथ संभावित नुकसान एक वर्ग को दोबारा शुरू करने के बाद आता है जिसमें static वर्ग के रूप में घोषित करने के लिए केवल स्थिर विधियां शामिल हैं, और एप्लिकेशन शुरू करते समय अजीब समस्याएं आ रही हैं।सी #

मैंने कोई पूरी तरह से जांच नहीं की है लेकिन ऐसा लगता है कि स्थिर निर्माता के भीतर से कुछ कॉल किए जा रहे हैं किसी कारण से पूरा नहीं होता है।

तो, मैं जानना चाहता हूं कि सी # में स्थिर रचनाकारों का उपयोग करते समय कोई नुकसान कहां है? अधिक विशेष रूप से, क्या ऐसी कोई चीजें हैं जिन्हें हर कीमत से बचा जाना चाहिए और स्थिर कन्स्ट्रक्टर के भीतर से उपयोग नहीं किया जाना चाहिए?

उत्तर

25

स्थिर रचनाकारों के लिए कई नुकसान हैं। उदाहरण के लिए, यदि एक स्थिर कन्स्ट्रक्टर throws an exception, तो आप TypeInitializationException प्राप्त करना जारी रखेंगे जब भी आप इसके किसी भी सदस्य तक पहुंचते हैं।

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

सामान्य रूप से, स्थिर वर्गों का उपयोग केवल स्टेटलेस परिदृश्यों में किया जाना चाहिए जहां आपको किसी भी प्रारंभिकरण की आवश्यकता नहीं होगी।

public class MyClass 
{ 
    private static readonly Lazy<MyClass> current = 
     new Lazy<MyClass>(() => new MyClass()); 

    public static MyClass Current 
    { 
     get { return current.Value; } 
    } 

    private MyClass() 
    { 
     // Initialization goes here. 
    } 

    public void Foo() 
    { 
     // ... 
    } 

    public void Bar() 
    { 
     // ... 
    } 
} 

static void Main(string[] args) 
{ 
    MyClass.Current.Foo(); // Initialization only performed here. 
    MyClass.Current.Bar(); 
    MyClass.Current.Foo(); 
} 

संपादित:: आपकी कक्षा प्रारंभ करने की आवश्यकता है, तो आप singleton pattern, का उपयोग कर से बेहतर है जो पहले उपयोग पर lazily initialized हो सकता है हो सकता है मैं कुछ आगे बात पर पढ़ने किया था, और यह प्रतीत होता है कि स्थैतिक रचनाकार यदि आप ब्लॉकिंग ऑपरेशंस (जैसे एसिंक्रोनस कॉलबैक या थ्रेड सिंक्रनाइज़ेशन) करते हैं तो डेडलॉक्स का कारण बनते हैं।

सीएलआर आंतरिक रूप से प्रकार प्रारंभकर्ताओं (स्थिर रचनाकारों) को कई बार निष्पादित करने से रोकने के लिए लॉकिंग का उपयोग करता है। इस प्रकार, यदि आपका स्थिर कन्स्ट्रक्टर किसी दूसरे धागे से अपने घोषित प्रकार के किसी अन्य सदस्य तक पहुंचने का प्रयास करता है, तो यह अनिवार्य रूप से डेडलॉक होगा। चूंकि "दूसरा सदस्य" एक पिनिंगक्यू या टीपीएल ऑपरेशन के हिस्से के रूप में घोषित एक अज्ञात फ़ंक्शन हो सकता है, इसलिए ये बग सूक्ष्म और पहचानने में कठोर हो सकती हैं।

इगोर Ostrovsky (MSFT) अपने Static constructor deadlocks लेख में इस बताते हैं, एक गतिरोध की निम्न उदाहरण प्रदान:

using System.Threading; 

class MyClass 
{ 
    static void Main() { /* Won’t run... the static constructor deadlocks */ } 

    static MyClass() 
    { 
     Thread thread = new Thread(arg => { }); 
     thread.Start(); 
     thread.Join(); 
    } 
} 

उपरोक्त उदाहरण में, नया थ्रेड खाली गुमनाम समारोह, { } का उपयोग करने की जरूरत है, परिभाषित इसके कॉलबैक के रूप में। हालांकि, चूंकि अज्ञात फ़ंक्शन को दृश्यों के पीछे MyClass की दूसरी निजी विधि के रूप में संकलित किया गया है, इसलिए नया थ्रेड MyClass प्रकार प्रारंभ होने से पहले इसका उपयोग नहीं कर सकता है। और, चूंकि MyClass स्थिर कन्स्ट्रक्टर को नए थ्रेड को पहले पूरा करने की प्रतीक्षा करनी है (thread.Join() की वजह से), एक डेडलॉक आ जाता है।

+0

क्या निर्माता के अंदर अपवादों के अलावा कुछ और है? उदाहरण के लिए, मैं "डेडलॉक" की व्याख्या कैसे कर सकता हूं जैसे परिदृश्य मैं अनुभव कर रहा हूं? क्या दृश्यों के पीछे किसी भी प्रकार स्थिर प्रकारों से जुड़ा कोई लॉकिंग है? –

+0

@liortal: ऊपर उत्तर दिया गया। – Douglas

+0

क्या आपके पहले उदाहरण में और इन लाइनों के बीच क्या कोई अंतर है? 'निजी स्थिर रीडोनली आलसी वर्तमान; स्थैतिक MyClass {वर्तमान = नया आलसी (() => नया MyClass()); } ' (क्षमा करें प्रपत्रण सही नहीं लग रहा है :)) – Mark

3

हां, कुछ नुकसान हैं, जो कक्षा शुरू होने पर संबंधित हैं। असल में, एक स्थिर कन्स्ट्रक्टर वाले वर्ग को beforefieldinit ध्वज के साथ चिह्नित नहीं किया जाएगा, जो रनटाइम को बाद में इसे प्रारंभ करने की अनुमति देता है।

अधिक जानकारी के लिए this article पर एक नज़र डालें।

0

यह प्रश्न का उत्तर नहीं है, लेकिन यह एक टिप्पणी के लिए बहुत लंबा है, इसलिए मैं इसे यहां प्रदान करता हूं ...

जब से मैं static class निर्माण के लिए नहीं पता था, मैं योजना (सरलीकृत) एकमात्र के साथ मुझे प्रदान करने के लिए निम्नलिखित का इस्तेमाल किया है:

public class SomeSingleton { 
    static _instance; 
    static public SomeSingleton Instance { 
     get { 
      if (_instance==null) { 
       _instance=new SomeSingleton(); 
      } 
      return _instance; 
     } 
    } 
} 

बाद में, आप

SomeSingleton.Instance.MyProp = 3; 

और पहली के उपयोग का उपयोग Instance सदस्य आपके सिंगलटन का निर्माण करेगा।

मुझे लगता है कि अगर इस तरह के कई वर्ग उचित क्रम में किए जाते हैं तो सिंगलटन के तत्काल होने के बाद यह ठीक है।

+0

यह प्रश्न का उत्तर नहीं देता है ... और एक स्थिर वर्ग * नहीं * सिंगलटन जैसा ही है (उदाहरण के लिए आप एक स्थिर वर्ग को पैरामीटर के रूप में पास नहीं कर सकते हैं, जिसे आप सिंगलटन के साथ कर सकते हैं) –

+4

आपका प्रारंभिकरण है थ्रेड-सुरक्षित नहीं है। यदि 'थ्रेंस' संपत्ति को कई धागे द्वारा समवर्ती रूप से एक्सेस किया जाता है, तो उन्हें "सिंगलटन" के विभिन्न उदाहरण मिल सकते हैं। यह विशिष्ट मामलों में कोई समस्या हो सकती है या नहीं भी हो सकती है, लेकिन यह सामान्य रूप से सिंगलटन प्रतिमान को तोड़ देती है। यदि आप .NET 4 (या बाद में) पर हैं, तो आपको 'आलसी ' पर स्विच करना चाहिए; यदि नहीं, तो आपको प्रारंभिक सिंक्रनाइज़ करने के लिए 'लॉक' का उपयोग करने पर विचार करना चाहिए। – Douglas

+0

@ डगलस धन्यवाद। मैं लॉक का उपयोग करता हूं, क्योंकि मैं .NET 2.0 में हूं :) –