2010-11-03 10 views
5

दो वर्गों, एक ही सुपर क्लास के दोनों सन्तान, मान लें इस तरह:सशर्त ऑपरेटर भ्रमित हो जाता है, लेकिन क्यों?

MySuperClass p = myCondition ? new A() : new B(); 

संकलक शिकायत है कि ए और बी काम नहीं करतीं:

class MySuperClass{} 
class A : MySuperClass{} 
class B : MySuperClass{} 

फिर इस काम संकलक पारित नहीं होगा (सशर्त अभिव्यक्ति का प्रकार निर्धारित नहीं किया जा सकता है क्योंकि 'ए' और 'बी' [CS0173] के बीच कोई अंतर्निहित रूपांतरण नहीं है)। लेकिन वे दोनों प्रकार के MySuperClass हैं, इसलिए मेरी राय में यह काम करना चाहिए। यह नहीं कि यह एक बड़ा सौदा है; कंपाइलर को प्रबुद्ध करने के लिए यह एक साधारण कलाकार है। लेकिन निश्चित रूप से यह सी # कंपाइलर में एक झगड़ा है? क्या आप सहमत नहीं हैं?

+0

यह अक्सर पूछे जाने वाले प्रश्न हैं। उदाहरण के लिए http://stackoverflow.com/questions/2215745 या http://stackoverflow.com/questions/3150086 या http://stackoverflow.com/questions/858080 देखें। इस विषय पर मेरे लेख भी देखें: http://blogs.msdn.com/b/ericlippert/archive/tags/conditional+operator/ –

उत्तर

10

सशर्त के परिणाम एक ही प्रकार के होने चाहिए। वो नहीं हैं।

MSDN से, (: ऑपरेटर):

या तो first_expression और second_expression के प्रकार, एक ही होना चाहिए या एक अंतर्निहित रूपांतरण एक प्रकार से दूसरे मौजूद होना चाहिए।

के बाद से A और B एक ही प्रकार नहीं कर रहे हैं और आप एक अंतर्निहित रूपांतरण को परिभाषित किया है प्रतीत नहीं, संकलक शिकायत।

+3

हाँ, एक कलाकार जोड़ने का प्रयास करें: 'p = myCondition? (MySuperClass) नया ए(): (MySuperClass) नया बी(); ' – anthares

+1

@anthares - आपको वास्तव में उनमें से एक को डालने की आवश्यकता है और कंपाइलर बाकी को -> p = myCondition inferes? (MySuperClass) नया ए(): नया बी() –

+0

निश्चित रूप से वे हैं। वे MySuperClass दोनों हैं। वैसे; यह काम करता है: MySuperClass पी = myCondition? (MySuperClass) नया ए(): नया बी(); तो यह दो उम्मीदवारों में से एक को कास्ट करने के लिए पर्याप्त है ... जैसा कि मैंने कहा; *कोई बड़ी बात नहीं*। लेकिन अभी भी एक जिज्ञासा, imho। – BaBu

3

कंपाइलर एक सामान्य पूर्वजों की तलाश करने की कोशिश नहीं करता है, इसलिए आपको यह दिखाने के लिए एक स्पष्ट कलाकार की आवश्यकता है कि आप किस पूर्वज के साथ इसका इलाज करना चाहते हैं; आपके मामले में:

MySuperClass p = myCondition ? (MySuperClass)(new A()) : (MySuperClass)(new B()); 

इसका मतलब यह है कि सशर्त ऑपरेटर gthe एक ही प्रकार है, जो संकलक संतुष्ट returnin दोनों पक्षों है।

+0

आपके पास 'नया ए()' और 'नया बी()' के आसपास अनावश्यक संश्लेषण है, जो इसे मेरी आंखों में बदसूरत लग रहा है। –

4

कुछ दिलचस्प लेखों के लिए यह blog देखें, क्यों सी # कंपाइलर आपके लिए 'स्पष्ट' चीजें नहीं करता/करती है। ब्लॉग एरिक लिपर्ट द्वारा लिखा गया है, सी # कंपाइलर डेवलपर्स में से एक है।

+0

+1: यह मेरे पसंदीदा ब्लॉग्स में से एक है, –

+0

+1 दूसरा कथन, मुझे यह ब्लॉग बहुत उपयोगी लगता है! – pstrjds

+3

यदि आप अपने ब्लॉग से लिंक करने जा रहे हैं, तो कम से कम एक प्रासंगिक लेख खोजने के प्रयास में डाल दें। इस मामले में, इस प्रश्न के बारे में एरिक के लेख http://blogs.msdn.com/b/ericlippert/archive/2010/05/27/cast-operators-do-not-obey-the-distributive-law पर पाए जाएंगे .aspx और http://blogs.msdn.com/b/ericlippert/archive/2006/05/24/type-inference-woes-part-one.aspx दूसरों के बीच। – Brian

1

रोवलैंड शॉ ने इसे बहुत अच्छी तरह से समझाया, लेकिन यह देखने के लिए कि एक आम पूर्वज का उपयोग क्यों नहीं किया जाता है, इस पर विचार करें कि क्या होगा यदि दोनों कक्षाएं एक विशेष इंटरफेस को लागू करने के लिए भी होंगी। कंपाइलर सशर्त ऑपरेटर के प्रकार के लिए उपयोग करने में सक्षम नहीं होगा, और इसलिए इसे object का उपयोग करने के लिए मजबूर होना होगा। ? ऑपरेटर नियंत्रण सशर्त अभिव्यक्ति के प्रकार :

4

भाषा विनिर्देश

दूसरे और तीसरे ऑपरेंड, एक्स और y, की की धारा 7.14 के लिए देखो।

· x टाइप एक्स और वाई है प्रकार Y तो

ओ एक अंतर्निहित रूपांतरण (§6.1) X से Y तक मौजूद है, तो है, लेकिन नहीं Y से एक्स के लिए, तो Y प्रकार है सशर्त अभिव्यक्ति का।

o यदि एक अंतर्निहित रूपांतरण (§6।1) वाई से एक्स तक मौजूद है, लेकिन एक्स से वाई तक नहीं है, तो एक्स सशर्त अभिव्यक्ति का प्रकार है।

ओ अन्यथा, कोई अभिव्यक्ति प्रकार निर्धारित किया जा सकता है, और एक संकलन-समय त्रुटि होती है।

· यदि x और y का केवल एक एक प्रकार, और दोनों x और y है, areimplicitly कि प्रकार के लिए परिवर्तनीय की, तो उस सशर्त अभिव्यक्ति का प्रकार है।

· अन्यथा, कोई अभिव्यक्ति प्रकार निर्धारित नहीं किया जा सकता है, और एक संकलन-समय त्रुटि होती है।

अनिवार्य रूप से, ऑपरेंड एक-दूसरे के लिए परिवर्तनीय, पारस्परिक रूप से कुछ अन्य प्रकार के लिए परिवर्तनीय नहीं होना चाहिए।

यही कारण है कि आपको अपने उदाहरण में या नलिकाओं (int? foo = isBar ? 42 : (int?)null) जैसे मामलों में एक स्पष्ट कलाकार बनाने की आवश्यकता है। घोषणा प्रकार मूल्यांकन को प्रभावित नहीं करता है, संकलक को अभिव्यक्ति से इसे समझना चाहिए।

3

सशर्त ऑपरेटर (किसी भी अन्य ऑपरेटर के साथ) को उस प्रकार को परिभाषित करना है जिसकी अभिव्यक्ति दर्शाती है। सशर्त ऑपरेटर के मामले में, इसमें दो-चरणीय प्रक्रिया है:

  1. क्या एक ही प्रकार के ऑपरेंड हैं? यदि ऐसा है, तो अभिव्यक्ति का प्रकार है।
  2. क्या ऑपरेंड प्रकारों में से एक से दूसरे में एक अंतर्निहित रूपांतरण है (लेकिन दोनों दिशाओं में नहीं)? यदि ऐसा है, तो "अन्य" अभिव्यक्ति का प्रकार है।

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

आपके मामले में, जैसा कि आपने पाया है, आपको माता-पिता के माता-पिता में से किसी एक को ऊपर उठाने की आवश्यकता है। एक बार ऐसा करने के बाद, नियम 2.) संतुष्ट है (हमेशा एक विशिष्ट प्रकार से एक विशिष्ट विशिष्ट प्रकार से कम विशिष्ट प्रकार में एक अंतर्निहित रूपांतरण होता है)।

ध्यान दें कि आपको केवल एक ऑपरेंड में कलाकारों को लागू करने की आवश्यकता है, दोनों नहीं।

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