2012-09-21 10 views
6

निम्नलिखित कोड में, मैं एक रचनाकार में एक संरचना पास करता हूं जो कक्षा की अपेक्षा कर रहा है। यह संकलन और त्रुटि के बिना क्यों चलाता है (और वांछित आउटपुट का उत्पादन)?"जहां टी: कक्षा" संकलित समय या रन समय पर किसी भी तरह से लागू नहीं है?

class Program 
{ 
    static void Main() 
    { 
     var entity = new Foo { Id = 3 }; 
     var t = new Test<IEntity>(entity); // why doesn't this fail? 
     Console.WriteLine(t.Entity.Id.ToString()); 
     Console.ReadKey(); 
    } 
} 

public class Test<TEntity> where TEntity : class 
{ 
    public TEntity Entity { get; set; } 

    public Test(TEntity entity) 
    { 
     Entity = entity; 
    } 

    public void ClearEntity() 
    { 
     Entity = null; 
    } 
} 

public struct Foo : IEntity 
{ 
    public int Id { get; set; } 
} 

public interface IEntity 
{ 
    int Id { get; set; } 
} 

मैं अपने Main() पद्धति को बदलने इतना है कि यह ClearEntity() के लिए एक कॉल भी शामिल है, जिन्हें आप नीचे है, यह अभी भी कोई त्रुटि उत्पन्न करता है। क्यूं कर?

static void Main() 
{ 
    var entity = new Foo { Id = 3 }; 
    var t = new Test<IEntity>(entity); 
    Console.WriteLine(t.Entity.Id.ToString()); 
    t.ClearEntity(); // why doesn't this fail? 
    Console.ReadKey(); 
} 
+5

'फू' 'आईएनएनटीटी 'होने के कारण, इसे बॉक्स किया जाएगा। बॉक्सिंग उदाहरण एक वर्ग का एक उदाहरण है। – Humberto

+0

'एंटीटी' को 'TENTITY'' के रूप में परिभाषित किया गया है, जहां 'TENTITY: क्लास ', जो' आईएनएनटीटीआई 'लागू नहीं करता है, वह' t.Entity.Id' को कैसे संकलित कर सकता है? –

उत्तर

8

where TEntity : class बलों TEntity एक संदर्भ प्रकार हो सकता है, लेकिन इस तरह के IEntity के रूप में एक अंतरफलक एक संदर्भ प्रकार है।

यहाँ देखें: http://msdn.microsoft.com/en-us/library/d5x73970(v=vs.80).aspx

जहां टी: वर्ग | प्रकार तर्क तर्क किसी भी प्रकार, इंटरफ़ेस, प्रतिनिधि, या सरणी प्रकार

आपके दूसरे प्रश्न के संबंध में, आपको लगता है कि t.ClearEntity() विफल हो जाएगा क्योंकि यह एक चर के लिए शून्य को असाइन कर रहा है जिसका प्रकार एक मान प्रकार है, लेकिन यह मामला नहीं है। Entity का संकलन-समय प्रकार संदर्भ प्रकार IEntity है, और रनटाइम प्रकार (असाइनमेंट के बाद) शून्य प्रकार है। तो आपके पास Foo प्रकार का चर नहीं है लेकिन मूल्य null है।

+0

+1। अच्छा स्पष्टीकरण, धन्यवाद। इससे कुछ अच्छी संभावनाएं खुलती हैं जिन्हें मुझे नहीं पता था। – devuxer

+1

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

2
सी # दस्तावेज़ से

:

जहां टी: वर्ग

प्रकार तर्क किसी भी वर्ग, इंटरफ़ेस, प्रतिनिधि, या सरणी प्रकार सहित के लिए एक संदर्भ प्रकार, होना चाहिए। (नीचे नोट देखें।)

क्योंकि आप एक इंटरफ़ेस के माध्यम से संरचना को पार कर रहे हैं, फिर भी इसे संदर्भ प्रकार माना जाता है।

+0

क्योंकि इसे बॉक्स किया जा रहा है क्योंकि यह वास्तव में एक संदर्भ प्रकार है, ऐसा नहीं है कि यह एक मान प्रकार है जिसे केवल 'वर्ग' प्रतिबंध द्वारा फ़िल्टर नहीं किया जा रहा है। – Servy

1

.NET रनटाइम के भीतर, प्रत्येक गैर-शून्य मूल्य प्रकार में एक संबंधित संदर्भ प्रकार होता है (जिसे अक्सर "बॉक्स किए गए मान प्रकार" के रूप में जाना जाता है) जो System.ValueType से प्राप्त होता है। Object Foo = 5; कहने से वास्तव में Int32Foo में संग्रहीत नहीं होगा; इसके बजाय यह Int32 से जुड़े संदर्भ प्रकार का एक नया उदाहरण बनाएगा और उस उदाहरण के संदर्भ को संग्रहीत करेगा। एक सामान्य प्रकार पर class बाधा निर्दिष्ट करती है कि प्रश्न में प्रकार किसी प्रकार का संदर्भ प्रकार होना चाहिए, लेकिन यह स्वयं संभावना से बाहर नहीं है कि प्रकार को बॉक्स किए गए मान-प्रकार के उदाहरण के संदर्भ में उपयोग करने के लिए उपयोग किया जा सकता है। सामान्य प्रकार की बाधाओं के बाहर अधिकांश संदर्भों में, इंटरफ़ेस प्रकारों को कक्षा प्रकार के रूप में माना जाता है।

यह ध्यान रखना महत्वपूर्ण है कि केवल संदर्भ प्रकारों जैसे संग्रहीत बॉक्स प्रकार मान प्रकार नहीं हैं; वे संदर्भ प्रकारों की तरह व्यवहार करते हैं। उदाहरण के लिए, List<string>.Enumerator एक मान प्रकार है जो IEnumerator<string> लागू करता है। यदि किसी के पास List<string>.Enumerator प्रकार के दो चर हैं, तो एक दूसरे को कॉपी करने से गणना की स्थिति की प्रतिलिपि होगी, जैसे कि दो अलग-अलग और स्वतंत्र गणनाकर्ता होंगे जो एक ही सूची को इंगित करते हैं। IEnumerator<string> प्रकार के चर के उन चरों में से एक को कॉपी करना List<string.Enumerator से जुड़े बॉक्स किए गए मान प्रकार का एक नया उदाहरण बनाएगा और बाद वाले चर में उस नई ऑब्जेक्ट का संदर्भ देगा (जो एक तीसरा स्वतंत्र गणनाकर्ता होगा)।उस चर को IEnumerator<string> पर किसी अन्य प्रकार की प्रतिलिपि बनाना, हालांकि, मौजूदा ऑब्जेक्ट का संदर्भ संग्रहीत करेगा (क्योंकि IEnumerator<string> एक संदर्भ प्रकार है)।

सी # भाषा Object से प्राप्त होने वाले मूल्य प्रकारों का बहाना करने का प्रयास करती है, लेकिन नेट रनटाइम की गड़बड़ी के भीतर वे वास्तव में नहीं करते हैं। इसके बजाय, वे परिवर्तनीय प्रकार हैं जो System.ValueType से प्राप्त होते हैं (जो बदले में Object से प्राप्त होता है)। बाद के प्रकार एक प्रकार की बाधा को पूरा करेंगे, भले ही पूर्व लोग नहीं करेंगे। संयोग से, इसके नाम के बावजूद, System.ValueType वास्तव में एक वर्ग प्रकार है।

0

मैं, इसी तरह, मान लिया कि बाधा कीवर्ड class टाइप घोषणा शब्द class के समान वर्ग का मतलब है, लेकिन ऐसा नहीं है।

जैसा कि अन्य उत्तरों में बताया गया है, class शब्द यहां अधिक भारित है, जो मुझे सी # भाषा डिजाइन के लिए एक भयानक निर्णय लगता है। referencetype की तरह कुछ और उपयोगी होगा।

+0

एक और मौलिक समस्या यह है कि मूल्य-प्रकार भंडारण स्थान उन चीज़ों को पकड़ते हैं जो 'ऑब्जेक्ट' से प्राप्त होते हैं। बॉक्स किए गए मान प्रकार 'ऑब्जेक्ट' से प्राप्त होते हैं, लेकिन मूल्य-प्रकार संग्रहण स्थान उनको नहीं पकड़ते हैं। मूल रूप से, 'टी' पर एक 'वर्ग' बाधा का अर्थ है उदाहरण के बारे में दो चीजें 'टी foo;': (1) 'foo' का डिफ़ॉल्ट मान एक शून्य संदर्भ होगा; (2) 'foo.bar() '' t' पर' बार() 'विधि अधिनियम का आह्वान करेगा जिसमें' foo' संदर्भ होगा, उस विधि को 'foo'' तक पहुंच के बिना। उन चीजों को किसी भी अन्य प्रकार के वर्ग की तुलना में बॉक्स किए गए मूल्य प्रकारों से कम सच नहीं है। – supercat

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