2013-03-11 7 views
7

जहाँ तक मुझे पता है कि C# वर्चुअल स्थिर गुणों का समर्थन नहीं करता है। C# में ऐसे व्यवहार को कैसे कार्यान्वित करें?वर्चुअल स्थिर गुणों को कैसे कार्यान्वित करें?

मैं संग्रह करना चाहता हूं कि बेस क्लास के सभी व्युत्पन्न वर्गों को स्थिर संपत्ति को ओवरराइड करना होगा। एक व्युत्पन्न प्रकार हो रही है, मैं Identifier

Type t = typeof(DerivedClass); 
var identifier= (String) t.GetProperty("Identifier", BindingFlags.Static).GetValue(null, null); 
+0

स्थिर सदस्यों को ओवरडोड नहीं किया जा सकता है (या यह "ओवरराइड" है?) मेरी खराब अंग्रेजी क्षमा करें = ( –

+0

जैसा कि आपने कहा था, सी # इसका समर्थन नहीं करता है, इसलिए आप इसे कार्यान्वित नहीं कर सकते हैं। – Servy

+0

वैसे भी, आप इसके लिए क्या चाहते हैं? 'गुण' का उपयोग करके हासिल किया जा सकता है। –

उत्तर

1

आप अभी भी पांच साल के बारे में एक accpted जवाब बाद में की जरूरत नहीं है के लिए, मुझे इसे आजमाइए (फिर) जाने ..

मैंने कभी एक समाधान के रूप Curiously Recurring Template Pattern के बारे में सोचा है, लेकिन आप के बाद से ' विरासत के लिए BaseClass खोलेंगे यह एक अच्छा विचार नहीं होगा। क्यों आप बेहतर समझने के लिए Mr. Lippert's blogpost पर एक नज़र रखना चाहते हैं।

  • समाधान 1: आप रजिस्टर नहीं है, मैं पहचान नहीं पा रहे ..

    public abstract class BaseClass { 
        protected static void Register<U>(String identifier) where U : BaseClass { 
         m_identities.Add(typeof(U).GetHashCode(), identifier); 
        } 
    
        public static String GetIdentifier<U>() where U : BaseClass { 
         var t = typeof(U); 
         var identifier = default(String); 
         RuntimeHelpers.RunClassConstructor(t.TypeHandle); 
         m_identities.TryGetValue(t.GetHashCode(), out identifier); 
         return identifier; 
        } 
    
        static Dictionary<int, String> m_identities = new Dictionary<int, String> { }; 
    } 
    
    public class DerivedClassA:BaseClass { 
        static DerivedClassA() { 
         BaseClass.Register<DerivedClassA>("12dc2490-065d-449e-a199-6ba051c93622"); 
        } 
    } 
    
    public class DerivedClassB:BaseClass { 
        static DerivedClassB() { 
         BaseClass.Register<DerivedClassB>("9745e24a-c38b-417d-a44d-0717e10e3b96"); 
        } 
    } 
    

    परीक्षण:

    Debug.Print("{0}", BaseClass.GetIdentifier<DerivedClassA>()); 
    Debug.Print("{0}", BaseClass.GetIdentifier<DerivedClassB>()); 
    

यह है प्रकार शुरू करने के माध्यम से एक अपेक्षाकृत सरल पैटर्न आर। Register विधि केवल व्युत्पन्न कक्षा के संपर्क में है; और GetIdentifier और Register दोनों विधियों को BaseClass से व्युत्पन्न एक प्रकार तर्क के साथ बुलाया जाता है। यद्यपि हम व्युत्पन्न कक्षाओं को कुछ भी ओवरराइड करने के लिए बाध्य नहीं करते हैं, अगर यह स्वयं पंजीकृत नहीं होता है, तो GetIdentifier इसे पहचानता नहीं है और null देता है।

  • समाधान 2: इससे पहले कि आप अपनी पहचान दिखाने के लिए, मैं तुम्हें एक डिफ़ॉल्ट खरीदते हैं। जो भी आप सोचते हैं, मैं विश्वास करता हूं - जब तक कोई अस्पष्टता न हो।

    public abstract class BaseClass { 
        public abstract String Identifier { 
         get; 
        } 
    
        public static Type GetDerivedClass(String identifier) { 
         return m_aliases[identifier]; 
        } 
    
        public static String GetIdentifier(Type t) { 
         var value = default(String); 
    
         if(t.IsSubclassOf(typeof(BaseClass))) { 
          var key = t.GetHashCode(); 
    
          if(!m_identities.TryGetValue(key, out value)) { 
           value=""+key; 
           m_aliases.Add(value, t); 
           m_identities[key]=value; 
          } 
         } 
    
         return value; 
        } 
    
        static void UpdateAlias(BaseClass x) { 
         var t = x.GetType(); 
         var value = x.Identifier; 
         m_aliases.Add(value, t); 
         m_identities[t.GetHashCode()]=value; 
        } 
    
        protected BaseClass() { 
         BaseClass.UpdateAlias(this); 
        } 
    
        static Dictionary<String, Type> m_aliases = new Dictionary<String, Type> { }; 
        static Dictionary<int, String> m_identities = new Dictionary<int, String> { }; 
    } 
    

    public class DerivedClassA:BaseClass { 
        public override String Identifier { 
         get { 
          return "just text"; 
         } 
        } 
    } 
    
    public class DerivedClassB:BaseClass { 
        public override String Identifier { 
         get { 
          return "just text"; 
         } 
        } 
    } 
    

    और परीक्षण:

    public static void TestMethod() { 
        var idBeforeInstantiation = BaseClass.GetIdentifier(typeof(DerivedClassA)); 
        var y = new DerivedClassA { }; 
        var idAfterInstantiation = BaseClass.GetIdentifier(typeof(DerivedClassA)); 
    
        Debug.Print("B's: {0}", BaseClass.GetIdentifier(typeof(DerivedClassB))); 
        Debug.Print("A's after: {0}", idAfterInstantiation); 
        Debug.Print("A's before: {0}", idBeforeInstantiation); 
        Debug.Print("A's present: {0}", BaseClass.GetIdentifier(typeof(DerivedClassA))); 
    
        var type1 = BaseClass.GetDerivedClass(idAfterInstantiation); 
        var type2 = BaseClass.GetDerivedClass(idBeforeInstantiation); 
    
        Debug.Print("{0}", type2==type1); // true 
        Debug.Print("{0}", type2==typeof(DerivedClassA)); // true 
        Debug.Print("{0}", type1==typeof(DerivedClassA)); // true 
    
        var typeB=BaseClass.GetDerivedClass(BaseClass.GetIdentifier(typeof(DerivedClassB))); 
    
        var x = new DerivedClassB { }; // confilct 
    } 
    

जाहिर है यह एक अधिक जटिल समाधान है।जैसा कि आप idBeforeInstantiation और idAfterInstantiation देख सकते हैं, हालांकि, वे DerivedClassA के लिए मान्य पहचानकर्ता हैं। m_identities में प्रत्येक व्युत्पन्न वर्ग के लिए अंतिम अद्यतन पहचानकर्ता शामिल है और m_aliases व्युत्पन्न कक्षाओं के लिए सभी पहचानकर्ता उपनाम शामिल होंगे। चूंकि वर्चुअल और स्थिर वर्तमान में भाषा की एक विशेषता नहीं है (शायद कभी नहीं ..), अगर हम ओवरराइड करना चाहते हैं तो हमें कुछ कामकाज के माध्यम से इसे करना होगा। यदि आप समाधान 2 का चयन करेंगे, तो हो सकता है कि आप व्युत्पन्न कक्षाओं को एक ही प्रकार के लिए विभिन्न उपनामों को प्रदान करने से रोकने के लिए UpdateAlias पर अपने आप को लागू करना चाहें, हालांकि वे सभी वैध होंगे। परीक्षण में अंतिम बयान जानबूझकर पहचानकर्ताओं के संघर्ष का प्रदर्शन करने के लिए रखा जाता है।

इन दो समाधान के लिए ध्यान से की आपके विचार व्युत्पन्न वर्ग का दृष्टांत के लिए नहीं के लिए तैयार कर रहे हैं, उनमें से कोई भी कि आवश्यकता है।

4

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

कृपया this SO पोस्ट में उत्तर देखें। यदि आप ऐसी सुविधा लागू कर सकते हैं तो आपके पास गंभीर विरासत के साथ समस्याएं हो सकती हैं।

वहां किया गया, ऐसा किया गया। मेरे इंद्रियों पर फिर से आने के बाद, मैं नियमित विरासत दृष्टिकोण के लिए गया। मुझे लगता है कि आपको शायद वही करना चाहिए।

0

ऐसा करने का एक और तरीका है जिसके लिए कक्षा को पंजीकृत करने की आवश्यकता नहीं है, लेकिन थोड़ा अतिरिक्त काम करने की आवश्यकता है एक स्थिर वर्ग बनाना जो प्रत्येक व्युत्पन्न वर्ग प्रकार के लिए "स्थैतिक" डेटा रखता है और स्थिर/स्थिर स्थिर वर्ग से मूल्य। मुझे इस दृष्टिकोण के विनिर्देशों की व्याख्या करने दें।

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

आप एक आभासी क्षेत्र या संपत्ति हमेशा वर्ग (स्थिर) के प्रत्येक सदस्य के लिए एक ही है कि जरूरत है, एक गैर स्थिर संपत्ति है कि इस तरह एक "निरंतर" या स्थिर डेटा रिटर्न का उपयोग करें:

public static class MyStaticData 
{ 
    public static const string Class1String = "MyString1"; 
    public static const int Class1Int = 1; 
    public static const string Class2String = "MyString2"; 
    public static const int Class2Int = 2; 
    // etc... 
} 

public abstract class MyBaseClass 
{ 
    public abstract string MyPseudoVirtualStringProperty { get; } 
    public abstract int MyPseudoVirtualIntProperty { get; } 
} 

public class MyDerivedClass1 : My BaseClass 
{ 
    public override string MyPseudoVirtualStringProperty { get { return MyStaticData.Class1String; } } 
    public override int MyPseudoVirtualIntProperty { get { return MyStaticData.Class1Int } } 
} 

public class MyDerivedClass2 : My BaseClass 
{ 
    public override string MyPseudoVirtualStringProperty { get { return MyStaticData.Class2String; } } 
    public override int MyPseudoVirtualIntProperty { get { return MyStaticData.Class2Int } } 
} 
संबंधित मुद्दे