क्या सामान्य वर्ग के स्थिर सदस्य विशिष्ट उदाहरण से बंधे हैं?


85

यह एक वास्तविक प्रश्न की तुलना में अधिक प्रलेखन है। ऐसा लगता है कि एसओ पर अभी तक संबोधित नहीं किया गया है (जब तक कि मैं इसे याद नहीं करता), इसलिए यहां दिया गया है:

एक सामान्य वर्ग की कल्पना करें जिसमें एक स्थिर सदस्य है:

class Foo<T> {
    public static int member;
}

क्या प्रत्येक विशिष्ट वर्ग के लिए सदस्य का एक नया उदाहरण है, या सभी फू-प्रकार वर्गों के लिए केवल एक ही उदाहरण है?

इसे आसानी से इस तरह कोड द्वारा सत्यापित किया जा सकता है:

Foo<int>.member = 1;
Foo<string>.member = 2;
Console.WriteLine (Foo<int>.member);

परिणाम क्या है, और इस व्यवहार को कहां प्रलेखित किया गया है?


4
संक्षिप्त उत्तर: प्रत्येक वास्तविक वर्ग के लिए एक नया उदाहरण है , यानी प्रत्येक प्रकार के लिए एक T( Foo<int>और Foo<string>दो अलग-अलग वर्गों का प्रतिनिधित्व करते हैं, और प्रत्येक उदाहरण में एक उदाहरण होगा, लेकिन कई Foo<int>उदाहरण एकल उदाहरण साझा करेंगे member)। अधिक विस्तृत उदाहरण के लिए देखें: stackoverflow.com/a/38369256/336648
Kjartan

जवाबों:


92

एक staticफ़ील्ड को एक ही प्रकार के सभी उदाहरणों में साझा किया जाता है । Foo<int>और Foo<string>दो अलग-अलग प्रकार हैं। यह कोड की निम्नलिखित पंक्ति द्वारा सिद्ध किया जा सकता है:

// this prints "False"
Console.WriteLine(typeof(Foo<int>) == typeof(Foo<string>));

जहाँ से यह प्रलेखित किया गया है, निम्नलिखित धारा 1.6.5 फ़ील्ड्स में C # भाषा विशिष्टता (C # 3 के लिए) पाया गया है:

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

जैसा कि पहले बताया गया है; Foo<int>और Foo<string>एक ही वर्ग नहीं हैं; वे एक ही सामान्य वर्ग से निर्मित दो अलग-अलग वर्ग हैं। यह कैसे होता है यह उपर्युक्त दस्तावेज़ के खंड 4.4 में उल्लिखित है:

एक सामान्य प्रकार की घोषणा, अपने आप में, एक अनबाउंड जेनेरिक प्रकार को दर्शाता है, जिसका उपयोग "ब्लूप्रिंट" के रूप में किया जाता है, जो कई प्रकार के तर्कों को लागू करने के तरीके से होता है।


26
यदि आप C # और Java दोनों में विकसित होते हैं, तो यहां एक गोचा है। जबकि Foo<int>और Foo<String>सी # में विभिन्न प्रकार हैं, वे कर रहे हैं एक ही क्योंकि जेनरिक के साथ कैसे जावा सौदों (प्रकार विलोपन / संकलक चाल) के जावा में टाइप करें।
पॉवरलॉर्ड

अगर ऐसा होता तो क्या होता: फू <int> foo1 = new फू <int> (); foo1.member = 10; फू <int> foo2 = new फू <int> (); foo2.member = 20; यहाँ क्या हुआ?
सभी को

@ हर सदस्य के मूल्य को दोनों उदाहरणों के लिए बदल दिया जाएगा (और 20 हो जाएगा) क्योंकि वे एक ही प्रकार Foo <int> साझा करते हैं।
स्टास इवानोव

1
क्या होगा यदि आप एक गैर-जेनेरिक आधार वर्ग प्राप्त करते हैं जिसमें एक व्युत्पन्न सामान्य वर्ग में एक स्थिर सदस्य है? क्या यह अभी भी सच होगा?
ब्रेन २२

@StasIvanov, foo1.member 10 रहेगा और foo2.member 20 होगा। कृपया सत्यापित करें
SHRI

16

यहां समस्या वास्तव में यह है कि "जेनेरिक कक्षाएं" बिल्कुल भी कक्षाएं नहीं हैं।

सामान्य वर्ग की परिभाषाएं कक्षाओं के लिए सिर्फ टेम्पलेट हैं, और जब तक उनके प्रकार के मापदंडों को निर्दिष्ट नहीं किया जाता है, तब तक वे केवल पाठ का एक टुकड़ा (या मुट्ठी भर बाइट्स) हैं।

रनटाइम में, कोई भी टेम्पलेट के लिए एक प्रकार का पैरामीटर निर्दिष्ट कर सकता है, इस प्रकार इसे जीवन में लाया जा सकता है, और अब, पूरी तरह से निर्दिष्ट प्रकार का एक वर्ग बना सकता है। इसीलिए स्थैतिक गुण टेम्प्लेट-वाइड नहीं होते हैं, और इसीलिए आप List<string>और के बीच कास्ट नहीं कर सकते List<int>

यह संबंध थोड़े वर्ग-वस्तु संबंध को दर्शाता है। जैसे कक्षाएं तब तक मौजूद नहीं हैं * जब तक आप उनसे किसी वस्तु को तत्काल प्राप्त नहीं करते हैं, तब तक सामान्य कक्षाएं मौजूद नहीं होती हैं, जब तक कि आप टेम्पलेट के आधार पर एक वर्ग नहीं बनाते हैं।

PS यह घोषित करना काफी संभव है

class Foo<T> {
    public static T Member;
}

इससे यह स्पष्ट है कि स्थिर सदस्यों को साझा नहीं किया जा सकता है, क्योंकि टी विभिन्न विशेषज्ञता के लिए अलग है।


4

वे साझा नहीं हैं। यह सुनिश्चित नहीं है कि यह कहां से प्रलेखित है, लेकिन चेतावनी चेतावनी CA1000 ( सामान्य प्रकारों पर स्थिर सदस्यों की घोषणा न करें ) कोड को अधिक जटिल बनाने के जोखिम के कारण बस इसके खिलाफ चेतावनी देता है।


1
वाह, अभी तक एक और नियम मैं एफएक्स कॉप पर साथ नहीं मिलेगा।
मैथ्यू व्हिट

इसका दस्तावेज यहाँ है
NtFreX

3

सी # जेनरिक का कार्यान्वयन C ++ के अधिक करीब है। इन दोनों भाषाओं में MyClass<Foo>और MyClass<Bar>स्थिर सदस्यों को साझा न करें लेकिन जावा में वे करते हैं। C # और C ++ में MyClass<Foo>आंतरिक रूप से संकलन के समय पूरी तरह से नए प्रकार का निर्माण करता है जैसे कि जेनेरिक मैक्रोज़ की तरह हैं। आप आमतौर पर स्टैक ट्रेस, जैसे MyClass'1और में उनके उत्पन्न नाम देख सकते हैं MyClass'2। यही कारण है कि वे स्थिर चर साझा नहीं करते हैं। जावा में, जेनेरिक को गैर-सामान्य प्रकारों का उपयोग करके संकलक कोड बनाने की अधिक सरल विधि द्वारा कार्यान्वित किया जाता है और सभी प्रकारों को जोड़ दिया जाता है। तो MyClass<Foo>और MyClass<Bar>जावा में दो पूरी तरह से नया वर्ग पैदा न करें, इसके बजाय वे दोनों एक ही वर्ग के हैं MyClassनीचे और इसलिए वे स्थैतिक चर को साझा करें।


1

वे वास्तव में साझा नहीं हैं। क्योंकि सदस्य बिल्कुल उदाहरण के लिए नहीं है। एक स्थिर वर्ग का सदस्य वर्ग का ही होता है। इसलिए, यदि आपके पास MyClass.Number है तो यह सभी MyClass.Number ऑब्जेक्ट के लिए समान है क्योंकि यह ऑब्जेक्ट पर भी निर्भर नहीं करता है। आप किसी भी वस्तु के बिना भी MyClass.Number को कॉल या संशोधित कर सकते हैं।

लेकिन चूंकि Foo <int> Foo <string> के समान वर्ग नहीं है, इसलिए ये दो नंबर साझा नहीं किए जाते हैं।

इसे दिखाने के लिए एक उदाहरण:

TestClass<string>.Number = 5;
TestClass<int>.Number = 3;

Console.WriteLine(TestClass<string>.Number);  //prints 5
Console.WriteLine(TestClass<int>.Number);     //prints 3

-4

IMO, आपको इसे परीक्षण करने की आवश्यकता है, लेकिन मुझे लगता है कि

Foo<int>.member = 1;
Foo<string>.member = 2;
Console.WriteLine (Foo<int>.member);

उत्पादन होगा 1क्योंकि मुझे लगता है कि, संकलन के दौरान, कंपाइलर आपके द्वारा उपयोग किए जाने वाले प्रत्येक सामान्य वर्ग के लिए 1 वर्ग बनाता है (उदाहरण के लिए: Foo<int>और Foo<string>)।

लेकिन मैं 100% सुनिश्चित नहीं हूं =)।

टिप्पणी: मुझे लगता है कि इस तरह की स्थिर विशेषताओं का उपयोग करने के लिए यह एक अच्छा डिज़ाइन नहीं है और न ही एक अच्छा अभ्यास है।


6
यदि 100% निश्चित नहीं है
sll
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.