2008-12-19 11 views
19

आप जेनेरिक सिंगलटन के लिए इस बारे में क्या सोचते हैं?एक सामान्य सिंगलटन

using System; 
using System.Reflection; 

// Use like this 
/* 
public class Highlander : Singleton<Highlander> 
{ 
    private Highlander() 
    { 
     Console.WriteLine("There can be only one..."); 
    } 
} 
*/ 

public class Singleton<T> where T : class 
{ 
    private static T instance; 
    private static object initLock = new object(); 

    public static T GetInstance() 
    { 
     if (instance == null) 
     { 
      CreateInstance(); 
     } 

     return instance; 
    } 

    private static void CreateInstance() 
    { 
     lock (initLock) 
     { 
      if (instance == null) 
      { 
       Type t = typeof(T); 

       // Ensure there are no public constructors... 
       ConstructorInfo[] ctors = t.GetConstructors(); 
       if (ctors.Length > 0) 
       { 
        throw new InvalidOperationException(String.Format("{0} has at least one accesible ctor making it impossible to enforce singleton behaviour", t.Name)); 
       } 

       // Create an instance via the private constructor 
       instance = (T)Activator.CreateInstance(t, true); 
      } 
     } 
    } 
} 
+8

नाम हाइलैंडर नाम के लिए +1 ;-) –

+0

यह लॉकिंग तकनीक तब तक टूट जाती है जब तक लॉकिंग ऑब्जेक्ट के लिए अस्थिर कीवर्ड का उपयोग नहीं किया जाता है। [यह] देखें (http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html) –

+0

codereview.stackexchange.com – MPelletier

उत्तर

28

एक सिंगलटन वर्ग बनाने के लिए केवल कोड की कुछ लाइनें है, और एक सामान्य सिंगलटन मैं हमेशा कोड की उन पंक्तियों के बारे में बनाने की कठिनाई के साथ।

public class Singleton 
{ 
    private Singleton() {} 
    static Singleton() {} 
    private static Singleton _instance = new Singleton(); 
    public static Singleton Instance { get { return _instance; }} 
} 

private static Singleton _instance = new Singleton(); 

लाइन, लॉकिंग के लिए की जरूरत को हटा के रूप में एक स्थिर निर्माता धागा सुरक्षित है।

+5

के लिए ठीक सवाल। विशेष रूप से जेनेरिक संस्करण वास्तव में आपको एक सिंगलटन नहीं देता है ... –

+1

आपको शायद एक स्थिर कन्स्ट्रक्टर भी जोड़ना चाहिए। देखें http://www.yoda.arachsys.com/csharp/singleton.html –

+0

दरअसल। और आलसी लोडिंग के लिए, जॉन का पेज भी उस नेस्टेड क्लास के साथ कवर करता है। –

5

खैर, यह वास्तव में सिंगलटन नहीं है - जब से तुम T नियंत्रित नहीं कर सकते, वहाँ के रूप में कई T उदाहरणों के रूप में आप की तरह हो सकता है।

(हटाया धागा दौड़, विख्यात की दोबारा जांच कर उपयोग)

5

मैंने अपना पिछला उत्तर हटा दिया है क्योंकि मैंने कोड को नहीं देखा है जो गैर-सार्वजनिक रचनाकारों के लिए जांच करता है। हालांकि, यह एक चेक है जो केवल निष्पादन समय पर किया जाता है - संकलन-समय चेक नहीं है, जो इसके खिलाफ एक स्ट्राइक है। यह गैर-सार्वजनिक कन्स्ट्रक्टर को कॉल करने के लिए पर्याप्त पहुंच रखने पर भी निर्भर करता है, जो कुछ सीमाएं जोड़ता है।

इसके अलावा, यह आंतरिक कंस्ट्रक्टर्स निषेध नहीं करता - तो आप गैर एकमात्र के साथ खत्म हो सकता है।

मैं व्यक्तिगत रूप से सरल थ्रेड सुरक्षा के लिए एक स्थिर निर्माता में भी उदाहरण बनाउंगा।

असल में मैं एक प्रशंसक नहीं हूं - सिंगलटन कक्षाएं बनाना बहुत आसान है, और आपको वैसे भी ऐसा नहीं करना चाहिए। एकमात्र के परीक्षण के लिए एक दर्द, decoupling आदि हैं

+1

सहमत; ज्यादातर मामलों में, एक स्थिर वर्ग अधिक उपयुक्त है। इंटरफेस आदि को लागू करने के लिए उपयोगी है, लेकिन मानक पैटर्न जेनरिक की जरूरत के बिना ठीक काम करता है। –

+2

लिंक को मत भूलना ... जॉन! :) http://www.yoda.arachsys.com/csharp/singleton.html – kenny

+0

@kenny: यह लिंक बस मैं क्या जरूरत है। धन्यवाद!! – fourpastmidnight

5

यह नेट 4

public class Singleton<T> where T : class, new() 
    { 
     Singleton(){} 

     private static readonly Lazy<T> instance = new Lazy<T>(()=> new T()); 

     public static T Instance { get { return instance.Value; } } 
    } 

और यह उपयोग कर रहा है का उपयोग कर मेरी बात पीछा कर रहा है है:

public class Adaptor 
    { 
    public static Adaptor Instance { get { return Singleton<Adaptor>.Instance;}} 
    } 
+3

इस दृष्टिकोण के साथ समस्या यह है कि यह सिंगलटन को लागू करने वर्ग के लिए एक सार्वजनिक निर्माता है, जो एक सिंगलटन उदाहरण के सीमा के बाहर उपयोग के संभावना की अनुमति देता है की आवश्यकता है (यानी संकलन समय रोकथाम यहां मौजूद नहीं है)। – sweetfa

+0

यह इसकी जेनेरिक की लागत है। – Alexandr

+1

हाँ, बस स्पष्ट किए जाने के लिए noob हालांकि जरूरत – sweetfa

1

AndreasN जवाब और जॉन स्कीट के "Fourth version - not quite as lazy, but thread-safe without using locks विलय "सिंगलटन सी # कार्यान्वयन के लिए, सभी कड़ी मेहनत करने के लिए कोड स्निपेट का उपयोग क्यों न करें:

<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> 
    <CodeSnippet Format="1.0.0"> 
     <Header> 
      <Title>Singleton Class</Title> 
      <Author>TWSoft</Author> 
      <Description>Generates a singleton class</Description> 
      <SnippetTypes> 
       <SnippetType>Expansion</SnippetType> 
      </SnippetTypes> 
      <Keywords> 
       <Keyword>Singleton</Keyword> 
      </Keywords> 
      <Shortcut>singleton</Shortcut> 
     </Header> 
     <Snippet> 
      <Declarations> 
       <Literal> 
        <ID>ClassName</ID> 
        <ToolTip>Replace with class name</ToolTip> 
        <Default>MySingletonClass</Default> 
       </Literal> 
      </Declarations> 

      <Code Language="CSharp"> 
       <![CDATA[ 
       public class $ClassName$ 
       { 
        #region Singleton 
        static readonly $ClassName$ mInstance = new $ClassName$(); 

        // Explicit static constructor to tell C# compiler 
        // not to mark type as beforefieldinit 
        static $ClassName$() 
        { 
        } 

        private $ClassName$() 
        { 
        } 

        public static $ClassName$ Instance 
        { 
         get { return mInstance; } 
        } 
       #endregion 
       } 
       ]]> 
      </Code> 
     </Snippet> 
    </CodeSnippet> 
</CodeSnippets> 

फिर आप इसे एक .snippt फ़ाइल में सहेज सकते हैं, और उसे वीएस आईडीई (टूल्स-> कोड स्निपेट्स मैनेजर)

-1

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

public sealed class Adaptor 
{ 
    private static readonly Lazy<Adaptor> instance = new Lazy<Adaptor>(() => new Adaptor()); 

    public static Adaptor Instance { get { return instance.Value; } } 

    private Adaptor() { } 
} 

आप एक अलग सामान्य सिंगलटन में ठीक से इस refactor नहीं कर सकते हैं होने के लिए आप एक आलसी सिंगलटन की जरूरत है और आवश्यकता होती है।

यह भी देखें: http://csharpindepth.com/Articles/General/Singleton.aspx

0

एक सामान्य सिंगलटन कारखाने के साथ एक समस्या है, क्योंकि यह सामान्य है, तो आप, singleton प्रकार है कि instantiated है को नियंत्रित नहीं करते तो आप कभी नहीं गारंटी ले सकते हैं कि उदाहरण आपके द्वारा बनाए गए आवेदन में एकमात्र उदाहरण होगा।

तो, आप एक सामान्य सिंगलटन कारखाना नहीं बना सकते - यह पैटर्न ही नजरअंदाज करता है।

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