2009-11-03 11 views
9

विफल:क्या कोई अच्छा कारण है कि सी # में टर्नरी सीमित क्यों हैं?

object o = ((1==2) ? 1 : "test"); 

में सफलता:

object o; 
if (1 == 2) 
{ 
    o = 1; 
} 
else 
{ 
    o = "test"; 
} 

पहले बयान में त्रुटि है:

सशर्त अभिव्यक्ति का प्रकार निर्धारित नहीं किया जा सकता है, क्योंकि 'पूर्णांक के बीच कोई अंतर्निहित रूपांतरण है वहाँ 'और' स्ट्रिंग '।

हालांकि ऐसा करने की आवश्यकता क्यों है, मैं उन मानों को एक प्रकार के ऑब्जेक्ट को आवंटित कर रहा हूं।

संपादित करें: उपरोक्त उदाहरण, तुच्छ है हाँ, लेकिन वहाँ है, जहां यह काफी मददगार होगा उदाहरण हैं:

int? subscriptionID; // comes in as a parameter 

EntityParameter p1 = new EntityParameter("SubscriptionID", DbType.Int32) 
{ 
    Value = ((subscriptionID == null) ? DBNull.Value : subscriptionID), 
} 
+0

क्या आप अपने प्रश्न के शीर्षक में टाइपो को ठीक कर सकते हैं, धन्यवाद। मेरे पास इसे संपादित करने के लिए पर्याप्त प्रतिष्ठा नहीं है। –

+0

फिक्स –

+4

के लिए धन्यवाद आपके दूसरे उदाहरण में आप लिख सकते हैं: value = subscription आईडी ?? DBNull.Value; –

उत्तर

17

उपयोग:

object o = ((1==2) ? (object)1 : "test"); 

मुद्दा है कि वापसी प्रकार सशर्त ऑपरेटर का असहनीय रूप से निर्धारित नहीं किया जा सकता है। यह कहना है कि, int और स्ट्रिंग के बीच, कोई सर्वश्रेष्ठ विकल्प नहीं है। कंपाइलर हमेशा सही अभिव्यक्ति के प्रकार का उपयोग करेगा, और यदि आवश्यक हो तो झूठी अभिव्यक्ति को स्पष्ट रूप से डालेगा।

संपादित करें: आप दूसरे उदाहरण में:

int? subscriptionID; // comes in as a parameter 

EntityParameter p1 = new EntityParameter("SubscriptionID", DbType.Int32) 
{ 
    Value = subscriptionID.HasValue ? (object)subscriptionID : DBNull.Value, 
} 

पुनश्च: '। त्रिगुट ऑपरेटर'
यही नहीं बुलाया जाता है यह एक टर्नरी ऑपरेटर है, लेकिन इसे 'सशर्त ऑपरेटर' कहा जाता है।

+0

विस्तृत करने के लिए, '1' एक आदिम प्रकार है, इसलिए आपको इसे निर्दिष्ट करने से पहले इसे किसी ऑब्जेक्ट पर डालना होगा। –

+0

क्या प्राइमेटिव्स सी # में ऑब्जेक्ट प्राप्त करते हैं? – Wells

+0

@ वेल्स वे वैल्यू टाइप से प्राप्त होते हैं, और क्योंकि आप इसे किसी ऑब्जेक्ट पर कास्टिंग कर रहे हैं वहां कुछ मुक्केबाजी चल रही है। – Joseph

2

फीचर एक्स इस तरह का जवाब देने के लिए अक्सर एक कठिन सवाल क्यों है। वास्तविक व्यवहार का जवाब देना बहुत आसान है।

मेरा शिक्षित अनुमान क्यों है। सशर्त ऑपरेटर को संक्षेप में और 2 संबंधित मूल्यों के बीच चयन करने के लिए एक बूलियन अभिव्यक्ति का उपयोग करने की अनुमति है। उन्हें संबंधित होना चाहिए क्योंकि उनका उपयोग एक ही स्थान पर किया जा रहा है। यदि उपयोगकर्ता इसके बजाय 2 असंबंधित मानों को चुनता है तो शायद वहां कोड में एक सूक्ष्म टाइपो/बग था और संकलक स्पष्ट रूप से वस्तु को कास्टिंग करने के बजाए इसे चेतावनी देने से बेहतर होता है। जो कुछ ऐसा हो सकता है जिसकी उन्होंने अपेक्षा नहीं की थी।

0

"int" एक आदिम प्रकार है, एक वस्तु नहीं है जबकि "स्ट्रिंग" को "आदिम वस्तु" के अधिक माना जाता है। जब आप "ऑब्जेक्ट ओ = 1" जैसे कुछ करते हैं, तो आप वास्तव में "Int32" को "int" मुक्केबाजी कर रहे हैं।

http://msdn.microsoft.com/en-us/magazine/cc301569.aspx

आम तौर पर, मुक्केबाजी की वजह से प्रदर्शन खो देता है कि पता लगाने के लिए मुश्किल है बचा जाना चाहिए: यहाँ मुक्केबाजी बारे में एक लेख के लिए एक लिंक है।

जब आप एक टर्नरी अभिव्यक्ति का उपयोग करते हैं, तो संकलक असाइनमेंट चर को बिल्कुल नहीं देखता है कि अंतिम प्रकार क्या है। संकलक क्या कर रहा है में अपना मूल विवरण तोड़ने के लिए:

विवरण: ऑब्जेक्ट ओ = ((1 == 2)?1: "परीक्षण");

संकलक:

  1. क्या हैं "1" और "परीक्षण" में '((1 == 2) 1: "परीक्षण")' के प्रकार? क्या वे मेल खाते हैं?
  2. क्या # 1 से अंतिम प्रकार 'ऑब्जेक्ट ओ' के लिए असाइनमेंट ऑपरेटर प्रकार से मेल खाता है?

चूंकि कंपाइलर # 2 तक # 2 का मूल्यांकन नहीं करता है, यह विफल रहता है।

15

हालांकि अन्य उत्तरों सही हैं, इस अर्थ में कि वे सच और प्रासंगिक बयान देते हैं, यहां भाषा डिजाइन के कुछ सूक्ष्म बिंदु हैं जिन्हें अभी तक व्यक्त नहीं किया गया है। सशर्त ऑपरेटर के वर्तमान डिजाइन में कई अलग-अलग कारक योगदान करते हैं।

सबसे पहले, यह एक स्पष्ट प्रकार के लिए जितना संभव हो उतना अभिव्यक्ति के लिए वांछनीय है जिसे अभिव्यक्ति की सामग्री से पूरी तरह से निर्धारित किया जा सकता है। यह कई कारणों से वांछनीय है। उदाहरण के लिए: यह इंटेलिसेन्स इंजन को बहुत आसान बनाता है। आप x.M(some-expression. टाइप करते हैं और इंटेलिसेन्स को कुछ अभिव्यक्ति का विश्लेषण करने में सक्षम होना चाहिए, इसके प्रकार का निर्धारण करें, और इंटेलिसेन्स से पहले एक ड्रॉपडाउन उत्पन्न करें, यह पता है कि x.M किस विधि को संदर्भित करता है। IntelliSense यह नहीं जान सकता कि x.M क्या निश्चित रूप से संदर्भित करता है कि एम को सभी तर्कों को तब तक अधिभारित किया जाता है जब तक कि यह सभी तर्कों को नहीं देखता है, लेकिन आपने अभी तक पहले तर्क में टाइप नहीं किया है।

दूसरा, हम सटीक परिदृश्य के कारण "अंदर से बाहर" प्रवाह करने के लिए प्रकार की जानकारी पसंद करते हैं: अधिभार संकल्प। निम्नलिखित पर विचार करें:

void M(object x) {} 
void M(int x) {} 
void M(string x) {} 
... 
M(b ? 1 : "hello"); 

यह क्या करना चाहिए? क्या यह वस्तु अधिभार को कॉल करना चाहिए? क्या इसे कभी-कभी स्ट्रिंग ओवरलोड को कॉल करना चाहिए और कभी-कभी int ओवरलोड को कॉल करना चाहिए? क्या होगा यदि आपके पास एक और ओवरलोड था, तो M(IComparable x) कहें - आप इसे कब चुनते हैं?

चीजें "दोनों तरीकों से बहती है" टाइप करते समय चीजें बहुत जटिल होती हैं। कह रहा है, "मैं इस वस्तु को प्रकार ऑब्जेक्ट के चर के लिए असाइन कर रहा हूं, इसलिए संकलक को पता होना चाहिए कि ऑब्जेक्ट को चुनने के लिए ठीक है" टाइप नहीं है; यह अक्सर ऐसा होता है कि हम उस वैरिएबल के प्रकार को नहीं जानते हैं जिसे आप असाइन कर रहे हैं क्योंकि हम को समझने की कोशिश करने की प्रक्रिया में हैं। ओवरलोड रिज़ॉल्यूशन वास्तव में पैरामीटर के प्रकारों को काम करने की प्रक्रिया है, जो तर्क हैं कि आप तर्कों के प्रकार से तर्कों को निर्दिष्ट कर रहे हैं। यदि तर्क के प्रकार उन प्रकारों पर निर्भर करते हैं जिन पर उन्हें असाइन किया जा रहा है, तो हमारे तर्क में हमारे पास एक परिपत्र है।

टाइप जानकारी लैम्बडा अभिव्यक्तियों के लिए "दोनों तरीकों का प्रवाह" करती है; कार्यान्वयन ने मुझे कुशलतापूर्वक एक वर्ष का बेहतर हिस्सा लिया। मैंने एक संकलक को डिजाइन करने और कार्यान्वित करने में कुछ कठिनाइयों का वर्णन करने वाले लेखों की एक लंबी श्रृंखला लिखी है जो विश्लेषण कर सकते हैं जहां संदर्भ सूचना के आधार पर जटिल अभिव्यक्तियों में टाइप की जाती है जिसमें अभिव्यक्ति संभवतः उपयोग की जा रही है; भाग एक यहाँ है:

http://blogs.msdn.com/ericlippert/archive/2007/01/10/lambda-expressions-vs-anonymous-methods-part-one.aspx

संभव है कि आप कहते हैं कि "ठीक है, ठीक है, मैं देख रहा हूँ क्यों तथ्य यह है कि मैं विरोध करने संकलक द्वारा सुरक्षित रूप से नहीं किया जा सकता है बताए रहा हूँ, और मैं देख रहा हूँ क्यों इसके लिए आवश्यक है अभिव्यक्ति का एक स्पष्ट प्रकार है, लेकिन अभिव्यक्ति ऑब्जेक्ट का प्रकार क्यों नहीं है, क्योंकि int और स्ट्रिंग दोनों ऑब्जेक्ट में परिवर्तनीय हैं?"यह मुझे मेरे तीसरे बिंदु पर लाता है:

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

इस डिजाइन के फैसले का कारण यह है कि सामान्य मनुष्यों के लिए यह काम करना आसान हो जाता है कि कंपाइलर किसी भी स्थिति में क्या करने जा रहा है जहां सबसे अच्छा प्रकार निर्धारित किया जाना चाहिए; यदि आप जानते हैं कि एक प्रकार जो सही है, आपको चेहरे पर घूर रहा है, तो इसे चुना जा रहा है, यह जानने के लिए बहुत आसान है कि क्या होने जा रहा है।

यह हमें कई जटिल नियमों को पूरा करने से भी बचाता है कि विवाद होने पर प्रकारों के सेट का सबसे अच्छा सामान्य प्रकार क्या है। मान लीजिए कि आपके पास {Foo, Bar} प्रकार हैं, जहां दोनों वर्ग आईबीएलए लागू करते हैं, और दोनों वर्ग बाज़ से प्राप्त होते हैं। आईबीएलए का सबसे अच्छा आम प्रकार कौन सा है, जो दोनों लागू होते हैं, या बाज़, दोनों का विस्तार होता है? हम इस सवाल का जवाब नहीं देना चाहते हैं; हम इसे पूरी तरह से टालना चाहते हैं।

अंत में, मुझे लगता है कि सी # कंपाइलर वास्तव में कुछ अस्पष्ट मामलों में गलत प्रकार के निर्धारण का दृढ़ संकल्प प्राप्त करता है। इस बारे में मेरा पहला लेख यहाँ है:

http://blogs.msdn.com/ericlippert/archive/2006/05/24/type-inference-woes-part-one.aspx

यह वास्तव में संकलक यह सही करता है और कल्पना गलत है कि विवाद-योग्य है; कार्यान्वयन डिजाइन मेरी राय में spec'd डिजाइन से बेहतर है।

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

+0

धन्यवाद एरिक। मैंने बस पहले अनुच्छेद को पढ़ा और सोच रहा था कि क्या टाइप करते समय इंटेलिजेंस सही अधिभार की पहचान कर सकता है? उदाहरण के लिए यदि मेरे पास प्रदर्शन नामक एक विधि है, तो केवल 1 तर्क, स्ट्रिंग, इंट, फ्लोट, साइज इत्यादि का तर्क ले सकता है, जो मैं उपयोग के प्रकार का उपयोग कर सही अधिभार जानकारी टूलटिप पर इंटेलिजेंस स्क्रॉल करता हूं? तो अगर मैं प्रदर्शन (myString) का उपयोग करता हूं, तो यह तुरंत प्रदर्शन (स्ट्रिंग) के लिए टूलटिप दिखाएगा? अभी यह केवल स्क्रॉलिंग है जब तर्कों की संख्या बदल जाती है। –

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

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