अजीब वापसी वाक्यविन्यास कथन


106

मुझे पता है कि यह अजीब लग सकता है, लेकिन मुझे यह भी नहीं पता है कि इंटरनेट में इस सिंटैक्स को कैसे खोजा जाए और मुझे यह भी पता नहीं है कि वास्तव में इसका क्या मतलब है।

इसलिए मैंने कुछ MoreLINQ कोड देखे हैं और फिर मैंने इस तरीके को देखा

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));

    return _(); IEnumerable<TSource> _()
    {
        var knownKeys = new HashSet<TKey>(comparer);
        foreach (var element in source)
        {
            if (knownKeys.Add(keySelector(element)))
                yield return element;
        }
    }
}

यह विचित्र वापसी कथन क्या है? return _();?


6
या तुम्हारा मतलब है return _(); IEnumerable<TSource> _():?
एलेक्स के।

6
@ सच, ​​मुझे आश्चर्य है कि अगर ओपी की return _(); IEnumerable<TSource> _()तुलना में अधिक का जिक्र है yield return?
रोब

5
मुझे लगता है कि वह इस लाइन का मतलब था return _(); IEnumerable<TSource> _()। वह वास्तविक रिटर्न स्टेटमेंट के बजाय जिस तरह से दिखता है, उससे भ्रमित हो सकता है।
मेटुस

5
@ आकाशवाणी ओपी ने कहा कि एक अजीब वापसी बयान था। दुर्भाग्य से, कोड में दो रिटर्न स्टेटमेंट शामिल हैं। तो यह समझ में आता है अगर लोग भ्रमित हैं कि वह किसके बारे में बात कर रहा है।
mjwills

5
प्रश्न संपादित किया, और एक बार फिर भ्रम के लिए खेद है।
कुस्कमेन

जवाबों:


106

यह C # 7.0 है जो स्थानीय कार्यों का समर्थन करता है ...।

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
       this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
    {
        if (source == null) throw new 
           ArgumentNullException(nameof(source));
        if (keySelector == null) throw 
             new ArgumentNullException(nameof(keySelector));

        // This is basically executing _LocalFunction()
        return _LocalFunction(); 

        // This is a new inline method, 
        // return within this is only within scope of
        // this method
        IEnumerable<TSource> _LocalFunction()
        {
            var knownKeys = new HashSet<TKey>(comparer);
            foreach (var element in source)
            {
                if (knownKeys.Add(keySelector(element)))
                    yield return element;
            }
        }
    }

करंट C # के साथ Func<T>

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
       this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
    {
        if (source == null) throw new 
           ArgumentNullException(nameof(source));
        if (keySelector == null) throw 
             new ArgumentNullException(nameof(keySelector));

        Func<IEnumerable<TSource>> func = () => {
            var knownKeys = new HashSet<TKey>(comparer);
            foreach (var element in source)
            {
                if (knownKeys.Add(keySelector(element)))
                    yield return element;
            }
       };

        // This is basically executing func
        return func(); 

    }

ट्रिक है, _ () का उपयोग करने के बाद घोषित किया जाता है, जो पूरी तरह से ठीक है।

स्थानीय कार्यों का प्रतीकात्मक उपयोग

उपरोक्त उदाहरण इनलाइन पद्धति का उपयोग कैसे किया जा सकता है इसका सिर्फ एक प्रदर्शन है, लेकिन सबसे अधिक संभावना है कि अगर आप सिर्फ एक बार विधि को लागू करने जा रहे हैं, तो इसका कोई फायदा नहीं है।

लेकिन ऊपर दिए गए उदाहरण में, जैसा कि फूली और लुआण द्वारा टिप्पणियों में उल्लेख किया गया है , स्थानीय फ़ंक्शन का उपयोग करने का एक फायदा है। चूंकि उपज वापसी के साथ कार्य निष्पादित नहीं किया जाएगा, जब तक कि कोई इसे पुनरावृत्त नहीं करता है, इस मामले में स्थानीय फ़ंक्शन के बाहर विधि को निष्पादित किया जाएगा और पैरामीटर सत्यापन भी किया जाएगा, भले ही कोई भी मूल्य को पुनरावृत्त नहीं करेगा।

कई बार हमने विधि में कोड दोहराया है, इस उदाहरण को देखें।

  public void ValidateCustomer(Customer customer){

      if( string.IsNullOrEmpty( customer.FirstName )){
           string error = "Firstname cannot be empty";
           customer.ValidationErrors.Add(error);
           ErrorLogger.Log(error);
           throw new ValidationError(error);
      }

      if( string.IsNullOrEmpty( customer.LastName )){
           string error = "Lastname cannot be empty";
           customer.ValidationErrors.Add(error);
           ErrorLogger.Log(error);
           throw new ValidationError(error);
      }

      ... on  and on... 
  }

मैं इसके साथ अनुकूलन कर सकता है ...

  public void ValidateCustomer(Customer customer){

      void _validate(string value, string error){
           if(!string.IsNullOrWhitespace(value)){

              // i can easily reference customer here
              customer.ValidationErrors.Add(error);

              ErrorLogger.Log(error);
              throw new ValidationError(error);                   
           }
      }

      _validate(customer.FirstName, "Firstname cannot be empty");
      _validate(customer.LastName, "Lastname cannot be empty");
      ... on  and on... 
  }

4
@ZoharPeled खैर .. पोस्ट कोड करता समारोह के लिए एक का उपयोग दिखाते हैं .. :)
रोब

2
@ColinM में से एक लाभ यह है कि अनाम फ़ंक्शन अपने 'होस्ट' से चर आसानी से एक्सेस कर सकता है।
mjwills

6
क्या आप सुनिश्चित हैं कि C # -स्पेक में यह वास्तव में एक अनाम फ़ंक्शन कहलाता है? ऐसा लगता है कि नाम है, अर्थात् _AnonymousFunctionया बस _, जबकि मैं एक वास्तविक अनाम फ़ंक्शन की अपेक्षा करता हूं कि कुछ ऐसा हो (x,y) => x+y। मैं इसे एक स्थानीय कार्य कहूंगा, लेकिन मैं C # शब्दावली का उपयोग नहीं कर रहा हूं।
चि।

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

6
@ColinM उदाहरण के लिए तैनात kuksmen वास्तव में मुख्य कारणों में से एक है जो अंततः इसे लागू किया गया था - जब आप एक फ़ंक्शन बनाते हैं yield return, तो कोई कोड तब तक निष्पादित नहीं किया जाता है जब तक कि गणना करने योग्य वास्तव में गणना नहीं की जाती है। यह अवांछनीय है, क्योंकि आप उदाहरण के लिए तर्कों को तुरंत सत्यापित करना चाहते हैं। सी # में ऐसा करने का एकमात्र तरीका विधि को दो तरीकों से अलग करना है - एक yield returnएस के साथ , और दूसरा बिना। इनलाइन विधियां आपको अव्यवस्था और संभावित दुरुपयोग से बचने के लिए अंदर कीyield विधि का उपयोग करने की अनुमति देती है , जो कि अपने माता-पिता के लिए कड़ाई से आंतरिक है और पुन: प्रयोज्य नहीं है।
लुआं

24

सरल उदाहरण पर विचार करें

void Main()
{
    Console.WriteLine(Foo()); // Prints 5
}

public static int Foo()
{
    return _();

    // declare the body of _()
    int _()
    {
        return 5;
    }
}

_() एक स्थानीय फ़ंक्शन है जो रिटर्न स्टेटमेंट वाले तरीके के भीतर घोषित किया गया है।


3
हां मुझे पता है कि स्थानीय कार्यों के बारे में यह प्रारूपण था जिसने मुझे बेवकूफ बनाया ... उम्मीद है कि यह फ्रेड नहीं बन जाएगा।
कुस्कमेन

20
क्या आपका मतलब है कि एक ही लाइन पर शुरू होने वाला फंक्शन डिक्लेरेशन? यदि हां, तो मैं सहमत हूं, यह भयानक है!
स्टुअर्ट

3
हां, मेरा यही मतलब है।
कुस्कमेन

9
सिवाय इसके कि यह अंडरस्कोर नामकरण के रूप में भयानक है
आइसपिकल जूल

1
@ आकाशवाणी: सवाल यह नहीं है कि क्या यह कानूनी सी # है, लेकिन क्या कोड को समझना आसान है (और इसलिए इसे बनाए रखना और पढ़ना आसान है) जब इस तरह का प्रारूप तैयार किया जाता है। व्यक्तिगत प्राथमिकताएं एक भूमिका निभाती हैं, लेकिन मैं स्टुअर्ट से सहमत हूं।
PJTraill
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.