14

मैंने हमेशा सोचा कि यह दोनों तरीकों से ठीक काम करता है। फिर इस परीक्षण किया और महसूस किया कि यह फिर से कार्य पर अनुमति नहीं है:फिर से असाइनमेंट पर संग्रह प्रारंभकर्ता क्यों नहीं हैं?

int[] a = {0, 2, 4, 6, 8}; 

ठीक काम करता है, लेकिन नहीं:

int [ ] a; 
a = { 0, 2, 4, 6, 8 }; 

इस के लिए कोई तकनीकी कारण? मैंने सोचा कि मैं इसके बारे में यहां पूछूंगा, क्योंकि यह व्यवहार मुझे सहजता से अपेक्षित था।

+4

आपको यह सहायक मिल सकता है: http://stackoverflow.com/questions/7351453/why-cant-i-use-the-array-initializer-with-an-implicitly-typed-variable (कड़ाई से डुप्लिकेट नहीं) –

उत्तर

20

सबसे पहले, चलो शर्तों सही पाने के काम करता है। यह संग्रह प्रारंभकर्ता नहीं है। यह सरणी प्रारंभकर्ता है। संग्रह संग्रहकर्ता हमेशा संग्रह प्रकार के लिए एक निर्माता का अनुसरण करता है। एक सरणी प्रारंभकर्ता केवल स्थानीय या फ़ील्ड घोषणा प्रारंभिक, या सरणी निर्माण अभिव्यक्ति में कानूनी है।

आप यह ध्यान में रखते हुए पूरी तरह से सही हैं कि यह एक अजीब नियम है। मुझे इसकी अजीबता को सटीक रूप से चिह्नित करने दें:

मान लें कि आपके पास एक विधि एम है जो स्याही की एक सरणी लेती है। इन सभी कानूनी हैं:

int[] x = new[] { 10, 20, 30 }; 
int[] y = new int[] { 10, 20, 30 }; 
int[] z = new int[3] { 10, 20, 30 }; 
M(new[] { 10, 20, 30 }); 
M(new int[] { 10, 20, 30 }); 
M(new int[3] { 10, 20, 30 }); 

लेकिन

int[] q = {10, 20, 30}; // legal! 
M({ 10, 20, 30 }); // illegal! 

ऐसा लगता है कि या तो "अकेला" सरणी प्रारंभकर्ता चाहिए लगता है हर जगह है कि "सजाया" एक है, या कहीं कानूनी किया जाना है। यह अजीब बात है कि यह छद्म अभिव्यक्ति है जो केवल प्रारंभकर्ता में वैध है, कहीं और नहीं कि एक अभिव्यक्ति कानूनी है।

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

तो, मुझे पहले कुछ कारण बताएं कि क्यों सरणी प्रारंभकर्ताओं को अभिव्यक्ति के रूप में अनुमति नहीं दी जानी चाहिए और स्थानीय चर प्रारंभकर्ताओं में अनुमति दी जानी चाहिए। तो मैं विपरीत के लिए कुछ कारण बताऊंगा।

कारण सरणी initializers अभिव्यक्ति के रूप में अनुमति नहीं दी जानी चाहिए:

सरणी initializers अच्छा संपत्ति है कि { हमेशा कोड का एक नया खंड की शुरूआत का मतलब उल्लंघन करते हैं। आईडीई में त्रुटि-वसूली पार्सर जो आपके द्वारा टाइप किए जाने वाले पार्स को ब्रेसिज़ का उपयोग करने के लिए एक सुविधाजनक तरीका के रूप में उपयोग करना पसंद करता है जब कोई कथन अधूरा होता है; यदि आप देखते हैं:

if (x == M(
{ 
    Q(

तो यह कोड संपादक अनुमान लगाने के लिए कि आप { से पहले )) याद कर रहे हैं बहुत आसान है। संपादक मान लेंगे कि Q( एक कथन की शुरुआत है और इसमें इसका अंत गुम है।

लेकिन अगर सरणी initializers कानूनी अभिव्यक्ति कर रहे हैं तो यह हो सकता है कि क्या याद आ रही है )})){}निम्नलिखितQ है।

दूसरा, अभिव्यक्ति के रूप में सरणी प्रारंभकर्ता अच्छे सिद्धांत का उल्लंघन करते हैं कि सभी ढेर आवंटन में कहीं भी "नया" होता है।

कारण सरणी initializers क्षेत्र और स्थानीय initializers में अनुमति दी जानी चाहिए:

याद रखें कि सरणी initializers सरणियों पर, v1.0 में भाषा को जोड़ा गया था इससे पहले कि परोक्ष टाइप किया स्थानीय लोगों, अनाम प्रकार, या प्रकार निष्कर्ष। दिन में वापस हम नहीं था सुखद "नई [] {10, 20, 30}" वाक्य रचना है, तो सरणी initializers के बिना आप कहता था:

int[] x = new int[] { 10, 20, 30 }; 

जो बहुत बेमानी लगता है! मैं देख सकता हूं कि वे वहां से "नया int []" क्यों प्राप्त करना चाहते थे।

जब आप कहते हैं कि

int[] x = { 10, 20, 30 }; 

यह वाक्य रचना अस्पष्ट नहीं है, पार्सर जानता है कि यह एक सरणी प्रारंभकर्ता है और कोड ब्लॉक की शुरुआत नहीं है (जैसा कि मैंने उपरोक्त वर्णित किया है।) न ही यह टाइप-संदिग्ध है; यह स्पष्ट है कि प्रारंभकर्ता संदर्भ से इंक की एक सरणी है।

तो तर्क तर्कसंगत है कि सी # 1.0 सरणी प्रारंभकर्ताओं को स्थानीय और फ़ील्ड प्रारंभकर्ताओं में क्यों अनुमति दी गई थी, लेकिन अभिव्यक्ति संदर्भों में नहीं।

लेकिन यह वह दुनिया नहीं है जिसे हम आज में हैं। क्या हम इसे आज स्क्रैच से डिजाइन कर रहे थे, शायद हमारे पास सरणी प्रारंभकर्ता नहीं होंगे जिनके पास "नया" नहीं है। आजकल निश्चित रूप से हम महसूस करते हैं कि बेहतर समाधान है:

var x = new[] { 10, 20, 30 }; 

और कहा कि अभिव्यक्ति किसी भी संदर्भ में मान्य है। यदि आप फिट देखते हैं तो आप इसे "घोषणा" पक्ष या = के "प्रारंभकर्ता" पक्ष पर स्पष्ट रूप से टाइप कर सकते हैं, या आप कंपाइलर को किसी भी तरफ या दोनों प्रकार के प्रकार का अनुमान लगा सकते हैं।

तो, संक्षेप में, हाँ, आप सही हैं कि यह असंगत है कि सरणी प्रारंभकर्ता केवल स्थानीय और क्षेत्र की घोषणाओं में ही हो सकते हैं लेकिन अभिव्यक्ति संदर्भों में नहीं। दस साल पहले इसका एक अच्छा कारण था, लेकिन आधुनिक दुनिया में टाइप अनुमान के साथ, इसके लिए अब कोई अच्छा कारण नहीं है। यह इस बिंदु पर सिर्फ एक ऐतिहासिक दुर्घटना है।

+4

वाह। यदि आपने प्रत्येक सी # प्रश्न का उत्तर पोस्ट किया है तो StackOverflow 1000x अधिक भयानक होगा। –

+0

@JimSchubert: मैं भावनाओं की बहुत सराहना करता हूं लेकिन मैं आपको आश्वासन देता हूं कि यह बदतर होगा। मुझे साइट पर 99% सी # प्रश्नों का उत्तर नहीं पता! मैं भाषा के इतिहास, डिजाइन और कार्यान्वयन पर एक विशेषज्ञ हूं; पिछले छह वर्षों से इस पर ध्यान केंद्रित करने का अर्थ है कि व्यावहारिक सी # प्रोग्रामिंग के विशाल क्षेत्र हैं जिन्हें मैं कुछ भी नहीं जानता। –

+0

वैसे भी, अपने उत्तरों को पढ़ने से प्यार है! – Matthias

1

यह सबसे:

int [] a;// ={1,2,3,4}; 
    a = new [] {1, 2, 3, 4}; 

वीबी में घोषणा के रूप में एक ही तरह से, आसान xD

Dim a() As Integer '={1,2,3,4} 
a = {1, 2, 3, 4} 
+1

वह पूछ रहा है कि यह प्रतिबंध क्यों मौजूद है। –

+0

धन्यवाद, 'नया []' पहले जोड़कर, यह काम करता है। लेकिन यह प्रतिबंध तब मौजूद क्यों है जब यह इसके बिना काम कर सके (जैसे कि जब आप इसे पहले असाइन करते हैं) –

+0

ठीक है, मुझे लगता है कि यह सिर्फ भाषा के लिए है, क्योंकि वीबी में यह किया जा सकता है, हमें एमएसआईएल कोड को देखना चाहिए जो दुविधा है । – Piyey

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