आउट चर में C # 7: अंडरस्कोर (_) और स्टार (*)


79

मैं यहाँ C # 7 में नई परिवर्तनशील विशेषताओं के बारे में पढ़ रहा था । मेरे दो सवाल हैं:

  1. इसे कहते हैं

    हम "के रूप में अच्छी तरह से मापदंडों के रूप में" डिस्कार्ड "की अनुमति देते हैं _, आपको उन मापदंडों को अनदेखा करने की अनुमति देता है जिनके बारे में आपको परवाह नहीं है:

    p.GetCoordinates(out var x, out _); // I only care about x
    

    प्रश्न: मुझे लगता है कि यह सिर्फ एक जानकारी है और C # 7 की नई विशेषता नहीं है क्योंकि हम ऐसा पूर्व C # 7.0 में भी कर सकते हैं:

    var _;
    if (Int.TryParse(str, out _))
    ...
    

    या मुझसे यहां कुछ छूट रहा है?

  2. जब मैं एक ही ब्लॉग में उल्लिखित करता हूं तो मेरा कोड एक त्रुटि देता है:

    ~Person() => names.TryRemove(id, out *);
    

    *मान्य पहचानकर्ता नहीं है। मैड्स टॉर्गेसेन द्वारा एक निरीक्षण मुझे लगता है?


15
में out _ _एक चर नहीं है, आप यह घोषणा नहीं है और आप नाम से इसका इस्तेमाल नहीं कर सकते हैं। में int _है कि एक चर रहा है।
ईव मार्क

9
तारांकन चिह्न वाइल्डकार्ड ने C # 7 की अंतिम रिलीज़ में ऐसा नहीं किया था, ऐसा लगता है।
माइकल Stum

3
@ निखिलअग्रवाल लेकिन वह अलग वाक्यविन्यास है। आपके प्रश्न में, आप का उपयोग करें out _, बिना var। इसके साथ varयह वास्तव में पहले जैसा ही है।
Evk

2
@ निखिलअग्रवाल जो वास्तव में किसी अजीब कारण से संकलन करता है। हालांकि, अगर विघटित कोड को देखें - यह असाइनमेंट बस वहां नहीं है, पूरी तरह से हटा दिया गया है। और अगर आप कुछ ऐसा करते हैं Console.WriteLine(_)- यह दावा नहीं करेगा कि ऐसा कोई चर नहीं है। काफी अजीब है। इससे भी अधिक: यदि आप कुछ ऐसा करते हैं _ = SomeMethodCall()- यह केवल SomeMethodCall()संकलित कोड द्वारा प्रतिस्थापित किया जाएगा । तो आखिर आप अब भी वास्तव में किसी सार्थक अर्थ में उस चर का उपयोग नहीं कर सकते।
Evk

जवाबों:


111

डिस्क्लेमर , C # 7 में जहाँ भी वैरिएबल घोषित किया जाता है, - से - जैसा कि नाम से पता चलता है - परिणाम को छोड़ दें। तो एक विचलन का उपयोग चर के साथ किया जा सकता है:

p.GetCoordinates(out var x, out _);

और इसका उपयोग अभिव्यक्ति परिणाम को छोड़ने के लिए किया जा सकता है:

_ = 42;

उदाहरण में,

p.GetCoordinates(out var x, out _);
_ = 42;

कोई चर नहीं है, _ पेश किया जा रहा है। एक त्याग के सिर्फ दो मामले हैं।

हालाँकि, यदि कोई पहचानकर्ता _दायरे में मौजूद है, तो उपयोग नहीं किया जा सकता है:

var _ = 42;
_ = "hello"; // error - a string cannot explicitly convert from string to int

इसका अपवाद तब होता है जब एक _चर का उपयोग एक बाहरी चर के रूप में किया जाता है। इस मामले में, संकलक प्रकार को अनदेखा varकरता है या इसे त्याग के रूप में मानता है:

if (p.GetCoordinates(out double x, out double _))
{
    _ = "hello"; // works fine.
    Console.WriteLine(_); // error: _ doesn't exist in this context.
}

ध्यान दें कि यह केवल तब होता है, यदि इस मामले में, out var _या out double _इसका उपयोग किया जाता है। बस का उपयोग करें out _और फिर इसे एक मौजूदा चर के संदर्भ के रूप में माना जाता है _, अगर यह दायरे में है, उदाहरण के लिए:

string _;
int.TryParse("1", out _); // complains _ is of the wrong type

अंत *में, डिस्कशन के आसपास की चर्चाओं में नोटेशन को जल्दी प्रस्तावित किया गया था, लेकिन _बाद में अन्य भाषाओं में अधिक सामान्यतः उपयोग किए जाने वाले नोटेशन के कारण इसे छोड़ दिया गया था


मुझे लगता है कि आप का मतलब है ... बाद में होने के _कारण ... '
martijnn2008

@ martijnn2008, अच्छी तरह से देखा जाता है। धन्यवाद।
डेविड अरनो

1
मुझे लगता है कि यह निहित है, लेकिन त्यागने की बात यह है कि इसका मूल्य वास्तव में संग्रहीत नहीं है?
सिंजई

यह कहते हुए कि _ = 42"त्याग [एस] अभिव्यक्ति परिणाम" भ्रामक है, क्योंकि _ = 42स्वयं मूल्य के साथ एक अभिव्यक्ति है 42, इसलिए कोई वास्तविक त्याग नहीं हो रहा है। अभी भी एक अंतर है क्योंकि _ = 42;एक बयान भी है, जबकि 42;ऐसा नहीं है, जो कुछ संदर्भों में मायने रखता है।
जीरोन मोस्टर्ट

1
यह वाक्यांश ठीक है, यह केवल यह _ = 42दिखाने में विफल रहता है कि इस हार का क्या मतलब है - यानी, जब आपको किसी अभिव्यक्ति को "स्टोर" नहीं करना होगा, लेकिन वैसे भी इसका मूल्यांकन करें, यह देखते हुए कि आप आमतौर पर कैसे मूल्यांकन कर सकते हैं (गैर-तुच्छ , उपयोगी) इसे संग्रहीत किए बिना अभिव्यक्ति ठीक है। मैं तुरंत अपने आप में एक उपयोगी उदाहरण के बारे में नहीं सोच सकता (और मुझे नहीं पता कि क्या एक है, या यदि यह व्याकरण में निरंतरता का परिणाम है)।
जेरेन मोस्टर्ट

30

_सी # 7 में डिसॉर्डर ऑपरेटर का एक और उदाहरण एक स्टेटमेंट में एक प्रकार के वेरिएबल से मिलान करना है , जिसे हाल ही में C # 7 में जोड़ा गया था:objectswitch

कोड:

static void Main(string[] args)
{
    object x = 6.4; 
    switch (x)
    {
        case string _:
            Console.WriteLine("it is string");
            break;
        case double _:
            Console.WriteLine("it is double");
            break;
        case int _:
            Console.WriteLine("it is int");
            break;
        default:
            Console.WriteLine("it is Unknown type");
            break;
    }

    // end of main method
}

यह कोड प्रकार से मेल खाएगा और पास किए गए चर को छोड़ देगा case ... _


14

अधिक जिज्ञासु के लिए

निम्नलिखित स्निपेट पर विचार करें

static void Main(string[] args)
{
    //....
    int a;
    int b;

    Test(out a, out b);
    Test(out _, out _);    
    //....
}

private static void Test(out int a, out int b)
{
    //...
}

यह क्या हो रहा है:

...

13:             int  a;
14:             int  b;
15: 
16:             Test(out a, out b);
02340473  lea         ecx,[ebp-40h]  
02340476  lea         edx,[ebp-44h]  
02340479  call        02340040  
0234047E  nop  
    17:             Test(out _, out _);
0234047F  lea         ecx,[ebp-48h]  
02340482  lea         edx,[ebp-4Ch]  
02340485  call        02340040  
0234048A  nop 

...

जैसा कि आप दृश्य के पीछे देख सकते हैं कि दो कॉल एक ही बात कर रहे हैं।

जैसा कि @ सर्व लॉरिजसेन ने कहा कि ठंडी बात यह है कि आपको उन चरों को पहले से घोषित नहीं करना है, जो कुछ मूल्यों में दिलचस्पी नहीं रखते हैं।


3
IL को समान होना चाहिए क्योंकि आप जिस फ़ंक्शन को कॉल कर रहे हैं उसके लिए अभी भी आउट चर के लिए स्लॉट्स की आवश्यकता है। यह सिर्फ इतना है कि नए त्यागने वाले वाक्यविन्यास का उपयोग करने से कंपाइलर को स्थानीय चर (या बल्कि) की कमी के बारे में और अधिक धारणा बनाने की अनुमति मिलती है, इसे अधिक कुशलता से उपयोग करने की अनुमति मिलती है (कम से कम सैद्धांतिक रूप से; मुझे नहीं पता कि क्या पहले से ही कोई अनुकूलन हैं। अब के रूप में संकलक में)।
प्रहार

9

पहले सवाल के बारे में

मुझे लगता है कि यह सिर्फ एक जानकारी है और C # 7 की नई विशेषता नहीं है क्योंकि हम ऐसा पूर्व C # 7.0 में भी कर सकते हैं।

var _;
if (Int.TryParse(str, out _))
    // ...

नवीनता यह है कि आपको _अभिव्यक्ति के अंदर या बाहर अब और घोषित नहीं करना है और आप बस टाइप कर सकते हैं

int.TryParse(s, out _);

यह एक लाइनर पूर्व C # 7 करने की कोशिश करें:

private void btnDialogOk_Click_1(object sender, RoutedEventArgs e)
{
     DialogResult = int.TryParse(Answer, out _);
}

7
जोड़ने के लिए: अंडरस्कोर, कई बाहर मानकों, जैसे के साथ तरीकों के लिए वास्तव में अच्छी तरह से काम करता है SomeMethod(out _, out _, out three)बाहर मापदंडों 3 है, लेकिन मैं की तरह चर बनाए बिना पहले दो बर्बाद कर रहा हूँ unused1, unused2आदि
माइकल Stum

@MichaelStum: यहाँ क्या हो रहा है? if (SomeMethod(out _, out _, out _)) _ = 5; कौन _इसे करने के लिए बात कर रहा है?
निखिल अग्रवाल

4
@ निखिलअग्रवाल एक _चर नहीं होगा , भले ही आप उपयोग करें out var _। ऐसा लगता है कि परिणाम को फेंकने के लिए अंडरस्कोर विशेष आवरण है।
माइकल Stum

0

C # 7.0 (मार्च 2017 के आसपास विजुअल स्टूडियो 2017) में, निम्नलिखित संदर्भों में असाइनमेंट में डिस्क्स का समर्थन किया जाता है:


अन्य उपयोगी नोट्स

  • डिस्क मेमोरी मेमोरी को कम कर सकते हैं। क्योंकि वे आपके कोड के इरादे को स्पष्ट करते हैं, वे इसकी पठनीयता और स्थिरता को बढ़ाते हैं
  • ध्यान दें कि _ एक मान्य पहचानकर्ता भी है। जब एक समर्थित संदर्भ के बाहर उपयोग किया जाता है

सरल उदाहरण: यहां हम 1 और 2 पैरा का उपयोग नहीं करना चाहते हैं और केवल 3 जी परम की जरूरत है

(_, _, area) = city.GetCityInformation(cityName);

स्विच केस में उन्नत उदाहरण जो आधुनिक स्विच केस पैटर्न मिलान ( स्रोत ) का उपयोग करता है

switch (exception)                {
case ExceptionCustom exceptionCustom:       
        //do something unique
        //...
    break;
case OperationCanceledException _:
    //do something else here and we can also cast it 
    //...
    break;
default:
    logger?.Error(exception.Message, exception);
    //..
    break;

}


0

क्यू: ... हम पूर्व C # 7.0 में भी ऐसा कर सकते हैं:

var _;
if (Int.TryParse(str, out _))

या मुझसे यहां कुछ छूट रहा है?

यह एक ही बात नहीं है।
आपका कोड एक असाइनमेंट बना रहा है।

C # 7.0 _ में एक वैरिएबल नहीं है, यह संकलक को मूल्य त्यागने के लिए कहता है
( जब तक कि आपने घोषित नहीं किया है _ को वेरिएबल किया है ... अगर आप ऐसा करते हैं कि वेरिएबल को डिसाइड सिंबल के बजाय इस्तेमाल किया जाता है)

उदाहरण: आप एक कोड के समान स्टिंग और एक इंट के रूप में _ का उपयोग कर सकते हैं :

string a; 
int b;
Test(out a, out b);
Test(out _, out _);

//...

void Test(out string a, out int b)
{
   //...
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.