C # में पैरामीटर मॉडिफायर का उपयोग कभी क्यों करेगा?


85

इसलिए, मैं (मुझे लगता है) समझता है कि inपैरामीटर संशोधक क्या करता है। लेकिन यह जो करता है वह काफी हद तक बेमानी लगता है।

आमतौर पर, मुझे लगता है कि उपयोग करने का एकमात्र कारण refकॉलिंग चर को संशोधित करना होगा, जो स्पष्ट रूप से मना किया गया है in। इसलिए inसंदर्भ से गुज़रना तार्किक रूप से मान से गुज़रने के बराबर लगता है।

क्या प्रदर्शन लाभ के कुछ प्रकार है? यह मेरा विश्वास था कि चीजों के पीछे-छोर पर, एक refपैरामीटर को कम से कम चर के भौतिक पते की प्रतिलिपि बनाना चाहिए, जो कि किसी भी विशिष्ट वस्तु संदर्भ के समान आकार होना चाहिए।

तो, क्या इसका फायदा सिर्फ बड़ी संरचनाओं में है, या क्या कुछ पीछे के कंपाइलर ऑप्टिमाइज़ेशन हैं जो इसे कहीं और आकर्षक बनाते हैं? यदि बाद में, मुझे हर पैरामीटर को क्यों नहीं बनाना चाहिए in?


1
हां, एक प्रदर्शन लाभ है। refपारित करने के लिए प्रयोग किया जाता है structs उन्हें कॉपी करने के बजाय संदर्भ द्वारा। inइसका मतलब है कि संरचना को संशोधित नहीं किया जाना चाहिए।
पनगीओटीस कानावोस

@dbc नहीं, इसका इंटरोप से कोई लेना-देना नहीं है
Panagiotis Kanavos

4
मूल्य प्रकारों के लिए प्रदर्शन। सी # 7.2 के लिए नया "इन-की
वर्ड

1
विस्तृत चर्चा यहाँ । अंतिम चेतावनी पर ध्यान दें:It means that you should never pass a non-readonly struct as in parameter.
पणगीतिस कानवास

मैं शपथ ले सकता था यह एक डुप्लिकेट था, लेकिन मैं इसे अब और नहीं ढूँढ सकता
JAD

जवाबों:


80

in को हाल ही में C # भाषा में पेश किया गया था।

inवास्तव में एक है ref readonly। आम तौर पर बोलना, केवल एक ही उपयोग का मामला होता है जहां inमददगार हो सकते हैं: उच्च प्रदर्शन वाले एप्स जो बहुत सारे बड़े readonly structएस के साथ काम करते हैं ।

आपके पास यह मानते हुए:

readonly struct VeryLarge
{
    public readonly long Value1;   
    public readonly long Value2;

    public long Compute() { }
    // etc
}

तथा

void Process(in VeryLarge value) { }

उस स्थिति में, VeryLargeइस संरचना में Processविधि का उपयोग करते समय रक्षात्मक प्रतियों का निर्माण किए बिना संरचना को संदर्भ द्वारा पारित किया जाएगा (जैसे कि कॉल करते समय value.Compute()), और संकलक द्वारा संरचना की अपरिवर्तनीयता सुनिश्चित की जाती है।

ध्यान दें कि structएक inसंशोधक के साथ नहीं-आसानी से गुजरने से कंपाइलर को संरचना के तरीकों को कॉल करने और उपरोक्त विधि में गुणों तक पहुंचने पर एक रक्षात्मक प्रतिलिपि बनाने का कारण होगा Process, जो प्रदर्शन को नकारात्मक रूप से प्रभावित करेगा!

वास्तव में अच्छा MSDN ब्लॉग प्रविष्टि है जिसे मैं ध्यान से पढ़ने की सलाह देता हूं।

यदि आप in-introducing की कुछ और ऐतिहासिक पृष्ठभूमि प्राप्त करना चाहते हैं , तो आप इस चर्चा को C # भाषा के GitHub भंडार में पढ़ सकते हैं ।

सामान्य तौर पर, अधिकांश डेवलपर्स सहमत होते हैं कि परिचय को inगलती के रूप में देखा जा सकता है। यह एक बल्कि विदेशी भाषा की विशेषता है और केवल उच्च-स्तरीय धार मामलों में उपयोगी हो सकती है।


क्या यह संकलक द्वारा उत्पन्न रक्षात्मक प्रतियों को दबा देता है, या केवल प्रोग्रामर की आवश्यकता को समाप्त करने के लिए मैन्युअल रूप से रक्षात्मक प्रतियों का निर्माण करता है जो अन्यथा उपयोग करेंगे ref, जैसे someProc(in thing.someProperty);बनाम अनुमति देकर propType myProp = thing.someProperty; someProc(ref myProp);? क्या inC # -ऑनलाइन कॉन्सेप्ट है out, या इसे .NET फ्रेमवर्क में जोड़ा गया है?
सुपरकट

@ सुपरकार्ट, आप एक गुण का उपयोग करके पास नहीं कर सकते in, क्योंकि inप्रभावी रूप refसे एक विशेष विशेषता के साथ है। तो आपका पहला स्निपेट संकलन नहीं करेगा। @VisualMelon, यह सही है, डिफेंसिव कॉपीिंग कॉलिंग मेथड्स या स्ट्रक्चर के प्रॉपर्टीज को एक्सेस करने के तरीके पर होती है जो स्ट्रक्चर को तर्क के रूप में प्राप्त करता है।
डाइनामॉइड

@dymanoid आपको स्पैम करने के लिए खेद है, यह समझने के लिए कि आपने जो लिखा है, उसे समझने के लिए मुझे लगभग 10 प्रयास करने पड़े (और मुझे नहीं लगता कि यह आपकी गलती है!)
VisualMelon

4
@dymanoid: दोनों inऔर outअवधारणाओं जो (एक साधन है जिसके द्वारा तरीकों और गुण का संकेत हो सकता है कि क्या वे modifiy के साथ शुरू से ही फ्रेमवर्क में किया जाना चाहिए था कर रहे हैं this)। एक संकलक एक संपत्ति inको एक अस्थायी होल्डिंग के संदर्भ में पारित करके एक तर्क को पारित करने की अनुमति दे सकता है; यदि दूसरी भाषा में लिखा गया कोई फ़ंक्शन उस अस्थायी को संशोधित करता है, तो शब्दार्थ थोड़ा सा icky होगा, लेकिन यह उस फ़ंक्शन के व्यवहार का दोष होगा जो उसके हस्ताक्षर से मेल नहीं खाता।
सुपरकैट

1
@ सुपरकैट, कृपया यहां चर्चा न खोलें (मैं वैसे भी .NET फ्रेमवर्क कॉन्सेप्ट टीम में नहीं हूं)। उत्तर में संदर्भित एक लंबी चर्चा है, और यह कि GitHub चर्चा कुछ अन्य का संदर्भ देती है - दिलचस्प पढ़ना। BTW, आप VB.NET में संपत्तियों को पास कर सकते हैं - संकलक आपके लिए उन अस्थायी कार्यों को बनाता है (जो निश्चित रूप से अस्पष्ट मुद्दों को जन्म दे सकता है)।
डाइनामॉइड

42

गुजर inसंदर्भ तार्किक मान द्वारा पारित करने के लिए बराबर है।

सही बात।

क्या प्रदर्शन लाभ का कुछ प्रकार है?

हाँ।

यह मेरा विश्वास था कि चीजों के पीछे-छोर पर, एक refपैरामीटर को कम से कम चर के भौतिक पते की प्रतिलिपि बनाना चाहिए, जो कि किसी भी विशिष्ट वस्तु संदर्भ के समान आकार होना चाहिए।

कोई आवश्यकता नहीं है कि एक वस्तु का संदर्भ और एक चर का संदर्भ दोनों एक ही आकार के हों, और एक आवश्यकता नहीं है कि या तो एक मशीन शब्द का आकार है, लेकिन हां, व्यवहार में दोनों 32 पर 32 बिट्स हैं 64 बिट मशीनों पर बिट मशीनें और 64 बिट्स।

आपको लगता है कि "भौतिक पता" के साथ क्या करना है यह मेरे लिए अस्पष्ट है। विंडोज पर हम वर्चुअल एड्रेस का उपयोग करते हैं , उपयोगकर्ता मोड कोड में भौतिक पते का नहीं । किन संभावित परिस्थितियों में आप कल्पना करेंगे कि C # कार्यक्रम में एक भौतिक पता सार्थक है, मुझे यह जानने की उत्सुकता है।

यह भी आवश्यकता नहीं है कि भंडारण के आभासी पते के रूप में किसी भी प्रकार का संदर्भ लागू किया जाए। संदर्भ सीएलआई विनिर्देश के अनुरूप कार्यान्वयन में जीसी तालिकाओं में अपारदर्शी हैंडल हो सकते हैं।

सिर्फ बड़े स्ट्रक्चर में फायदा है?

बड़ी संरचनाओं को पारित करने की लागत कम करना सुविधा के लिए प्रेरक परिदृश्य है

ध्यान दें कि कोई भी गारंटी नहीं है inजो किसी भी कार्यक्रम को वास्तव में तेज बनाता है, और यह कार्यक्रमों को धीमा कर सकता है। अनुभवजन्य शोध द्वारा प्रदर्शन के बारे में सभी सवालों का जवाब दिया जाना चाहिए । बहुत कम अनुकूलन हैं जो हमेशा जीतते हैं ; यह "हमेशा जीत" अनुकूलन नहीं है।

क्या कुछ पीछे-पीछे कंपाइलर ऑप्टिमाइज़ेशन है जो इसे कहीं और आकर्षक बनाता है?

कंपाइलर और रनटाइम को किसी भी अनुकूलन को बनाने की अनुमति है यदि वे ऐसा करते हैं तो सी # विनिर्देश के नियमों का उल्लंघन नहीं करते हैं। मेरी जानकारी में inमापदंडों के लिए अभी तक ऐसा अनुकूलन नहीं है , लेकिन यह भविष्य में इस तरह के अनुकूलन को रोकता नहीं है।

मुझे हर पैरामीटर को एक क्यों नहीं बनाना चाहिए?

ठीक है, मान लीजिए कि आपने एक intपैरामीटर के बजाय एक in intपैरामीटर बनाया है। क्या लागत लगाई जाती है?

  • कॉल साइट को अब एक मान के बजाय एक चर की आवश्यकता होती है
  • चर को अपंजीकृत नहीं किया जा सकता है। घबराने की सावधानी से किए गए रजिस्टर आवंटन योजना में सिर्फ एक रिंच मिला है।
  • कॉल साइट पर कोड बड़ा है, क्योंकि इसे वेरिएबल पर रेफरी लेना चाहिए और इसे स्टैक पर रखना चाहिए, जबकि इससे पहले कि यह कॉल स्टैक पर मूल्य को धक्का दे सकता है
  • बड़ा कोड का मतलब है कि कुछ छोटे कूद निर्देश अब लंबी कूद निर्देश बन सकते हैं, इसलिए, अब कोड बड़ा हो गया है। इससे सभी तरह की चीजों पर असर पड़ता है। कैश जल्दी भर जाता है, घबराने के लिए अधिक काम करना पड़ता है, घबराना बड़े कोड आकारों पर कुछ अनुकूलन नहीं करने का विकल्प चुन सकता है, और इसी तरह।
  • कैली साइट पर, हमने स्टैक (या रजिस्टर) पर एक मान को एक सूचक में अप्रत्यक्ष रूप से एक्सेस किया है। अब, वह पॉइंटर कैश में होने की अत्यधिक संभावना है, लेकिन फिर भी, हमने अब टू-इंस्ट्रक्शन एक्सेस में वैल्यू के लिए वन-इंस्ट्रक्शन एक्सेस को बदल दिया है।
  • और इसी तरह।

मान लीजिए कि यह एक है doubleऔर आप इसे ए में बदलते हैं in double। फिर, अब चर को उच्च-प्रदर्शन फ्लोटिंग पॉइंट रजिस्टर में नहीं देखा जा सकता है। यह न केवल प्रदर्शन के निहितार्थ है, यह कार्यक्रम के व्यवहार को भी बदल सकता है! सी # को उच्च-से-64-बिट सटीकता में फ्लोटिंग अंकगणित करने की अनुमति है और आमतौर पर ऐसा तभी होता है जब फ्लोट्स की गणना की जा सकती है।

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


"किस परिस्थिति में [...] संभव परिस्थितियों में आप कल्पना करेंगे कि एक C # कार्यक्रम में एक भौतिक पता सार्थक है, [...]।" । C # का उपयोग आमतौर पर ऐसे सिस्टम पर किया जाता है, जिनमें मैमोरी-मैप्ड I / O, और रिसेट वैक्टर जैसी चीजें होती हैं, मैं यहाँ सादे पुराने विंटेल बॉक्स के बारे में सोच रहा हूँ। X86 प्रोसेसर और वीजीए फ्रेमबफर्स ​​के साथ। ठीक है, आमतौर पर हम सीधे इन में हेरफेर नहीं करते हैं, लेकिन हम सही कर सकते हैं?
ओमरएल

5
क्या inवास्तव में सभी मामलों में मूल्य के हिसाब से पास करना बराबर है? यदि हमारे पास है f(ref T x, in T y)और fसंशोधित करता है x, तो इसे उसी बदलाव का निरीक्षण करना चाहिए yजब इसे लागू किया जाता है f(ref a,a)। यह भी लागू होता है अगर fएक in T yऔर एक प्रतिनिधि लेता है जो कि yजब बुलाया संशोधित होगा । इसके बिना in, शब्दार्थ भिन्न होगा, क्योंकि yइसका मान कभी नहीं बदला जाएगा, मुझे लगता है, क्योंकि यह एक प्रतिलिपि होगी।
ची

2
मुझे शक है कि अनौपचारिक रूप से ओपी का अर्थ "भौतिक पता" है, "मेमोरी स्थान का वर्णन करने वाला बिट-पैटर्न" के रूप में, इसके विपरीत "जो भी वस्तु खोजने के लिए उपयोग करने के लिए बैकेंड का उपयोग करने का विकल्प चुनता है"।
स्नेफेल

@Wilson: आप जिस बारे में बात कर रहे हैं उसका एक उदाहरण देखना मुझे अच्छा लगेगा; मैं किसी को भी नहीं जानता, जो C # में उन चीजों को करने का प्रयास करता है। एक "सिस्टम सी #" के वर्षों में कुछ बात हुई है, जिसके तहत उच्च-स्तरीय प्रबंधित भाषा का उपयोग निम्न-स्तरीय सिस्टम घटकों को लिखने के लिए किया जा सकता है, लेकिन मैंने वास्तव में कभी भी इस तरह के कोड को खुद नहीं देखा है।
एरिक लिपर्ट

2
@chi: यह सही है। अगर आप वेरिएबल अलियासिंग के साथ खतरनाक गेम खेलते हैं तो आप मुश्किल में पड़ सकते हैं। यदि ऐसा करने पर दर्द होता है, तो ऐसा न करें। इरादा के in"संदर्भ द्वारा, केवल पढ़ने के पास" की धारणा का प्रतिनिधित्व करते हैं, जो तार्किक रूप से मूल्य से गुजर के बराबर है है जब आप समझदारी से व्यवहार करते हैं
एरिक लिपर्ट

6

वहाँ है। पास करते समय struct, inकीवर्ड एक अनुकूलन की अनुमति देता है जहां संकलक को सामग्री को बदलने की विधि के जोखिम के बिना केवल एक पॉइंटर पास करने की आवश्यकता होती है। अंतिम महत्वपूर्ण है - यह एक कॉपी ऑपरेशन से बचा जाता है। बड़ी संरचनाओं पर यह अंतर की दुनिया बना सकता है।


2
यह केवल वही दोहरा रहा है जो प्रश्न पहले से ही कहता है, और जो वास्तविक प्रश्न पूछता है उसका उत्तर नहीं देता है।
सर्व

केवल पठनीय संरचनाओं में। अन्यथा कंपाइलर अभी भी एक रक्षात्मक प्रति बनाएगा
पनियागोटिस कानवास

1
दरअसल नहीं। यह पुष्टि कर रहा है कि एक कलाकार एबेनेस्साइट है। यह देखते हुए कि IN लैंग्वेज के माध्यम से चलने वाले प्रदर्शन में बनाया गया था, हाँ, यही कारण है। यह एक ऑप्टिमाइज़ेशन (रीडॉनली स्ट्रक्चर्स पर) दिखाता है।
टॉम टॉम

3
@TomTom अगेन, जिस पर पहले से ही सवाल था । यह क्या पूछता है, "तो, तो इसका फायदा केवल बड़ी संरचनाओं में है, या क्या कुछ पीछे-पीछे कंपाइलर ऑप्टिमाइज़ेशन है जो इसे कहीं और आकर्षक बनाता है? यदि बाद वाला है, तो मुझे हर पैरामीटर को एक में क्यों नहीं बनाना चाहिए?" ध्यान दें कि यह कैसे नहीं पूछ रहा है कि क्या यह वास्तव में बड़ी संरचनाओं के लिए फायदेमंद है, या जब यह बिल्कुल फायदेमंद है। यह सिर्फ पूछ रहा है कि क्या यह छोटी संरचनाओं के लिए फायदेमंद है (और यदि हां तो अनुवर्ती है)। आपने प्रश्न का उत्तर नहीं दिया है।
सर्व

2

यह कार्यात्मक प्रोग्रामिंग दृष्टिकोण के कारण किया जाता है। एक प्रमुख सिद्धांत यह है कि फ़ंक्शन के साइड इफेक्ट्स नहीं होने चाहिए, जिसका अर्थ है कि इसे मापदंडों के मूल्यों को नहीं बदलना चाहिए और कुछ मूल्य वापस करना चाहिए। C # में केवल संदर्भ द्वारा कॉपी किए बिना स्ट्रक्चर्स (और वैल्यू टाइप) पास करने का कोई तरीका नहीं था जो मूल्य को बदलने की अनुमति देता है। जब तक विधि अपने मूल्यों को बदलना शुरू नहीं करती है तब तक स्विफ्ट में एक हैकी एल्गोरिथ्म होता है, जो संरचना को कॉपी करता है (उनके संग्रह बीटीडब्ल्यू हैं)। जो लोग स्विफ्ट का उपयोग करते हैं वे सभी कॉपी सामान के बारे में नहीं जानते हैं। यह अच्छा c # फीचर है क्योंकि यह मेमोरी कुशल और स्पष्ट है। अगर तुम देखो क्या नया हैआप देखेंगे कि स्टैक में स्ट्रक्चर्स और सरणियों के आसपास अधिक से अधिक सामान किया जाता है। और बयान में इन सुविधाओं के लिए बस आवश्यक है। अन्य उत्तरों में उल्लिखित सीमाएँ हैं, लेकिन यह समझने के लिए आवश्यक नहीं है कि .net कहाँ है।


2

में यह # 7.2 ग में केवल पढ़ने के लिए संदर्भ है

इसका मतलब है कि आप संरचना के संदर्भ में पास होने वाले रेफरी के समान कार्य करने के लिए पूरी वस्तु को पास नहीं करते हैं

लेकिन वस्तु के मूल्य को बदलने का प्रयास संकलक त्रुटि देता है।

और हां यह आपको बड़ी संरचनाओं का उपयोग करने पर कोड प्रदर्शन को अनुकूलित करने की अनुमति देगा।

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