बनाम foreach बनाम LINQ के लिए


86

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

और अक्सर, जब मैं इस बदलाव को स्वीकार करता हूं, तो ReSharper एक कदम आगे बढ़ता है, और मुझे एक चमकदार लाइन के रूप में इसे फिर से बदलने का सुझाव देता है।

इसलिए, मुझे आश्चर्य है कि क्या इन सुधारों में कुछ वास्तविक फायदे हैं? बहुत सरल कोड निष्पादन में, मैं किसी भी गति को बढ़ावा नहीं दे सकता (स्पष्ट रूप से), लेकिन मैं कोड को कम और कम पठनीय देख सकता हूं ... तो मुझे आश्चर्य है कि क्या यह इसके लायक है?


2
यदि आप SQL सिंटैक्स से परिचित हैं तो बस एक नोट - LINQ सिंटैक्स वास्तव में बहुत पठनीय है। LINQ (SQL-like lambda एक्सप्रेशंस, और जंजीर के तरीके) के लिए दो प्रारूप भी हैं, जो सीखना आसान बना सकते हैं। यह सिर्फ रेस्परर के सुझाव हो सकते हैं जो इसे अपठनीय लगते हैं।
शौना

3
अंगूठे के एक नियम के रूप में, मैं आम तौर पर तब तक उपयोग करता हूं जब तक कि ज्ञात लंबाई सरणी या इसी तरह के मामलों के साथ काम न करें जहां पुनरावृत्तियों की संख्या प्रासंगिक है। LINQ-ifying के रूप में, मैं आमतौर पर देखूंगा कि ReSharper एक फॉर्च्यूनर का क्या बनाता है, और यदि परिणामी LINQ स्टेटमेंट छोटा / तुच्छ / पठनीय है तो मैं इसका उपयोग करता हूं, और अन्यथा मैं इसे वापस करता हूं। यदि आवश्यकताओं को बदल दिया जाए या यदि यह आवश्यक हो तो तर्क को गैर-LINQ तर्क को फिर से लिखने के लिए एक राग होगा यदि LINQ कथन को दूर से तर्क को अलग कर रहा है, तो मैं इसे LINQ नहीं कर रहा हूं और इसे लंबे समय तक छोड़ दूंगा प्रपत्र।
एड हेस्टिंग्स

इसके साथ एक आम गलती foreachयह है कि इसे forअंतिम रूप से शुरू करने के लिए आमतौर पर एक लूप की आवश्यकता होती है , जबकि इसे संग्रहित करते हुए एक संग्रह से आइटम निकाल रहा है ।
स्लैई

आप evredev 2013 से मूल्य ले सकते हैं - जेसिका केर - ऑब्जेक्ट-ओरिएंटेड डेवलपर्स के लिए कार्यात्मक सिद्धांत । लाइनक "डिक्लेरेटिव स्टाइल" शीर्षक के तहत 33 मिनट के निशान के तुरंत बाद लाइनक प्रस्तुति में आता है।
थरोट

जवाबों:


139

for बनाम foreach

एक आम भ्रम है कि दो निर्माण बहुत समान हैं और दोनों इस तरह विनिमेय हैं:

foreach (var c in collection)
{
    DoSomething(c);
}

तथा:

for (var i = 0; i < collection.Count; i++)
{
    DoSomething(collection[i]);
}

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

आइए देखें कि इसमें एक उदाहरण के साथ क्या गलत है। अंत में, आपको परिणामों को इकट्ठा करने के लिए उपयोग किए जाने वाले डेमो एप्लिकेशन का पूरा कोड मिलेगा।

उदाहरण में, हम "बोस्टन" का सामना करने से पहले, डेटाबेस से कुछ डेटा लोड कर रहे हैं, एडवेंचर वर्क्स के शहरों से, नाम से आदेश दिया गया है। निम्न SQL क्वेरी का उपयोग किया जाता है:

select distinct [City] from [Person].[Address] order by [City]

डेटा ListCities()विधि द्वारा लोड किया जाता है जो एक रिटर्न देता है IEnumerable<string>। यहाँ जैसा foreachदिखता है वैसा है:

foreach (var city in Program.ListCities())
{
    Console.Write(city + " ");

    if (city == "Boston")
    {
        break;
    }
}

चलो इसे फिर से लिखते हैं for, यह मानते हुए कि दोनों विनिमेय हैं:

var cities = Program.ListCities();
for (var i = 0; i < cities.Count(); i++)
{
    var city = cities.ElementAt(i);

    Console.Write(city + " ");

    if (city == "Boston")
    {
        break;
    }
}

दोनों एक ही शहर लौटते हैं, लेकिन बहुत बड़ा अंतर है।

  • उपयोग करते समय foreach, ListCities()एक समय कहा जाता है और 47 वस्तुओं की पैदावार होती है।
  • उपयोग करते समय for, ListCities()94 बार कहा जाता है और कुल मिलाकर 28153 वस्तुओं की पैदावार होती है।

क्या हुआ?

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

एक मामले में foreach, परिणाम केवल एक बार अनुरोध किया जाता है। उपरोक्त लिखित गलत कोड के रूप में कार्यान्वित होने की स्थिति में , परिणाम 94 बार अनुरोध किया जाता हैfor , अर्थात 47 × 2:

  • हर बार cities.Count()(47 बार) कहा जाता है,

  • हर बार cities.ElementAt(i)(47 बार) कहा जाता है।

एक के बजाय 94 बार डेटाबेस को छोड़ना भयानक है, लेकिन इससे भी बदतर चीज जो हो सकती है। उदाहरण के लिए, उदाहरण के लिए, यदि selectक्वेरी उस क्वेरी से पहले होगी, जो तालिका में एक पंक्ति सम्मिलित करती है , तो क्या होगा । ठीक है, हमारे पास forडेटाबेस को 2,147,483,647 बार कॉल करना होगा , जब तक कि यह उम्मीद से पहले दुर्घटनाग्रस्त न हो जाए।

बेशक, मेरा कोड पक्षपाती है। मैंने जानबूझकर आलस का इस्तेमाल किया IEnumerableऔर इसे बार-बार बुलाने के तरीके से लिखा ListCities()। एक नोट कर सकता है कि एक शुरुआतकर्ता ऐसा कभी नहीं करेगा, क्योंकि:

  • IEnumerable<T>संपत्ति नहीं है Count, लेकिन केवल विधि Count()। एक विधि को कॉल करना डरावना है, और कोई भी इसके परिणाम को कैश नहीं किया जा सकता है, और for (; ...; )ब्लॉक में उपयुक्त नहीं होने की उम्मीद कर सकता है ।

  • अनुक्रमण के लिए अनुपलब्ध है IEnumerable<T>और ElementAtLINQ एक्सटेंशन विधि को खोजने के लिए स्पष्ट नहीं है ।

संभवतया अधिकांश शुरुआती सिर्फ उसी ListCities()चीज के परिणाम को परिवर्तित करेंगे जिसके साथ वे परिचित हैं, जैसे List<T>

var cities = Program.ListCities();
var flushedCities = cities.ToList();
for (var i = 0; i < flushedCities.Count; i++)
{
    var city = flushedCities[i];

    Console.Write(city + " ");

    if (city == "Boston")
    {
        break;
    }
}

फिर भी, यह कोड foreachविकल्प से बहुत अलग है । फिर से, यह एक ही परिणाम देता है, और इस बार ListCities()विधि को केवल एक बार कहा जाता है, लेकिन 575 वस्तुओं की पैदावार होती है, जबकि इसके साथ foreach, यह 47 वस्तुओं का उत्पादन करता है।

अंतर इस तथ्य से आता है कि डेटाबेस से सभी डेटा लोड होने का ToList()कारण बनता है। जबकि "बोस्टन" से पहले केवल शहरों का अनुरोध किया गया था, नए को सभी शहरों को पुनः प्राप्त करने और स्मृति में संग्रहीत करने की आवश्यकता है। 575 छोटी स्ट्रिंग्स के साथ, शायद इससे बहुत फर्क नहीं पड़ता है, लेकिन क्या होगा अगर हम अरबों के रिकॉर्ड वाली तालिका से केवल कुछ पंक्तियों को पुनः प्राप्त कर रहे थे?foreachfor

तो foreachवास्तव में क्या है ?

foreachथोड़ी देर के पाश के करीब है। कोड जो मैंने पहले इस्तेमाल किया था:

foreach (var city in Program.ListCities())
{
    Console.Write(city + " ");

    if (city == "Boston")
    {
        break;
    }
}

बस द्वारा प्रतिस्थापित किया जा सकता है:

using (var enumerator = Program.ListCities().GetEnumerator())
{
    while (enumerator.MoveNext())
    {
        var city = enumerator.Current;
        Console.Write(city + " ");

        if (city == "Boston")
        {
            break;
        }
    }
}

दोनों एक ही आईएल का उत्पादन करते हैं। दोनों का परिणाम समान है। दोनों का एक ही साइड इफेक्ट है। बेशक, यह whileएक समान अनंत में फिर से लिखा जा सकता है for, लेकिन यह अधिक लंबा और त्रुटि-प्रवण होगा। आप अधिक पढ़ने योग्य खोजने के लिए स्वतंत्र हैं।

इसे स्वयं परखना चाहते हैं? यहाँ पूर्ण कोड है:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;

public class Program
{
    private static int countCalls;

    private static int countYieldReturns;

    public static void Main()
    {
        Program.DisplayStatistics("for", Program.UseFor);
        Program.DisplayStatistics("for with list", Program.UseForWithList);
        Program.DisplayStatistics("while", Program.UseWhile);
        Program.DisplayStatistics("foreach", Program.UseForEach);

        Console.WriteLine("Press any key to continue...");
        Console.ReadKey(true);
    }

    private static void DisplayStatistics(string name, Action action)
    {
        Console.WriteLine("--- " + name + " ---");

        Program.countCalls = 0;
        Program.countYieldReturns = 0;

        var measureTime = Stopwatch.StartNew();
        action();
        measureTime.Stop();

        Console.WriteLine();
        Console.WriteLine();
        Console.WriteLine("The data was called {0} time(s) and yielded {1} item(s) in {2} ms.", Program.countCalls, Program.countYieldReturns, measureTime.ElapsedMilliseconds);
        Console.WriteLine();
    }

    private static void UseFor()
    {
        var cities = Program.ListCities();
        for (var i = 0; i < cities.Count(); i++)
        {
            var city = cities.ElementAt(i);

            Console.Write(city + " ");

            if (city == "Boston")
            {
                break;
            }
        }
    }

    private static void UseForWithList()
    {
        var cities = Program.ListCities();
        var flushedCities = cities.ToList();
        for (var i = 0; i < flushedCities.Count; i++)
        {
            var city = flushedCities[i];

            Console.Write(city + " ");

            if (city == "Boston")
            {
                break;
            }
        }
    }

    private static void UseForEach()
    {
        foreach (var city in Program.ListCities())
        {
            Console.Write(city + " ");

            if (city == "Boston")
            {
                break;
            }
        }
    }

    private static void UseWhile()
    {
        using (var enumerator = Program.ListCities().GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
                var city = enumerator.Current;
                Console.Write(city + " ");

                if (city == "Boston")
                {
                    break;
                }
            }
        }
    }

    private static IEnumerable<string> ListCities()
    {
        Program.countCalls++;
        using (var connection = new SqlConnection("Data Source=mframe;Initial Catalog=AdventureWorks;Integrated Security=True"))
        {
            connection.Open();

            using (var command = new SqlCommand("select distinct [City] from [Person].[Address] order by [City]", connection))
            {
                using (var reader = command.ExecuteReader(CommandBehavior.SingleResult))
                {
                    while (reader.Read())
                    {
                        Program.countYieldReturns++;
                        yield return reader["City"].ToString();
                    }
                }
            }
        }
    }
}

और परिणाम:

--- के लिए ---
अबिंगडन अल्बानी अलेक्जेंड्रिया अल्हाम्ब्रा [...] बॉन बोर्डो बोस्टन

डेटा को 94 समय (सेकंड) कहा जाता था और 28153 आइटम (आइटम) प्राप्त होते थे।

--- सूची के साथ ---
अबिंगडन अल्बानी अलेक्जेंड्रिया अल्हाम्ब्रा [...] बॉन बोर्डो बोस्टन

डेटा को 1 बार (s) कहा गया और 575 आइटम (s) प्राप्त हुए।

--- जबकि ---
एबिंगडन अल्बानी अलेक्जेंड्रिया अल्हाम्ब्रा [...] बॉन बोर्डो बोस्टन

डेटा को 1 बार (s) कहा गया और 47 आइटम (s) प्राप्त हुए।

--- फ़ॉरच्यू ---
अबिंगडन अल्बानी अलेक्जेंड्रिया अल्हाम्ब्रा [...] बॉन बोर्डो बोस्टन

डेटा को 1 बार (s) कहा गया और 47 आइटम (s) प्राप्त हुए।

LINQ बनाम पारंपरिक तरीका

LINQ के लिए, आप कार्यात्मक प्रोग्रामिंग (FP) सीखना चाहते हैं - C # FP सामान नहीं, बल्कि असली FP भाषा जैसे Haskell। कार्यात्मक भाषाओं में कोड को व्यक्त करने और प्रस्तुत करने का एक विशिष्ट तरीका है। कुछ स्थितियों में, यह गैर-कार्यात्मक प्रतिमानों से बेहतर है।

जब सूची में हेरफेर करने की बात आती है, तो एफपी बहुत बेहतर माना जाता है ( सामान्य शब्द के रूप में सूची , असंबंधित List<T>)। इस तथ्य को देखते हुए, जब यह सूचियों की बात आती है तो C # कोड को अधिक कार्यात्मक तरीके से व्यक्त करने की क्षमता बल्कि एक अच्छी बात है।

यदि आप आश्वस्त नहीं हैं, तो विषय पर मेरे पिछले उत्तर में कार्यात्मक और गैर-कार्यात्मक दोनों तरीकों से लिखे गए कोड की पठनीयता की तुलना करें ।


1
ListCities () उदाहरण के बारे में प्रश्न। यह केवल एक बार ही क्यों चलेगा? मुझे अतीत में पैदावार प्रतिफल पर पहुंचने के लिए कोई समस्या नहीं थी।
दांते

1
वह यह नहीं कह रहा है कि आप केवल IEnumerable से एक परिणाम प्राप्त करेंगे - वह कह रहा है कि SQL क्वेरी (जो विधि का महंगा हिस्सा है) केवल एक बार निष्पादित करेगा - यह एक अच्छी बात है। यह तब क्वेरी से सभी परिणामों को पढ़ेगा और प्राप्त करेगा।
HappyCat

9
@ जिओर्जियो: जबकि यह प्रश्न समझ में आता है, एक भाषा का शब्दार्थ क्या है जो एक शुरुआत को भ्रामक लग सकता है और हमें एक बहुत प्रभावी भाषा के साथ नहीं छोड़ेगा।
स्टीवन एवर्स

4
LINQ सिर्फ शब्दार्थ चीनी नहीं है। यह विलंबित निष्पादन प्रदान करता है। और IQueryables के मामले में (जैसे एंटिटी फ्रेमवर्क) क्वेरी को पारित करने और बनाने के लिए अनुमति देता है जब तक कि यह पुनरावृत्त न हो (मतलब यह है कि एक लौटे हुए खंड को जोड़ने पर IQueryable का परिणाम होगा SQL में सर्वर पर पारित होने के लिए सर्वर पर पारित करने के लिए जहां यह खंड शामिल है सर्वर पर फ़िल्टरिंग को उतारना)।
माइकल ब्राउन

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

19

जबकि वहाँ और foreach के बीच के मतभेदों पर पहले से ही कुछ शानदार प्रदर्शन हैं। LINQ की भूमिका की कुछ गलत गलतियाँ हैं।

LINQ सिंटेक्स सिर्फ वाक्यगत शर्करा नहीं है जो C # को एक कार्यात्मक प्रोग्रामिंग सन्निकटन देता है। LINQ, C # के सभी लाभों सहित कार्यात्मक निर्माण प्रदान करता है। IList के बजाय IEnumerable को वापस करने के साथ संयुक्त, LINQ पुनरावृत्ति के आस्थगित निष्पादन प्रदान करता है। आम तौर पर अब जो लोग करते हैं, वे निर्माण करते हैं और इस तरह से अपने कार्यों से एक IList लौटाते हैं

public IList<Foo> GetListOfFoo()
{
   var retVal=new List<Foo>();
   foreach(var foo in _myPrivateFooList)
   {
      if(foo.DistinguishingValue == check)
      {
         retVal.Add(foo);
      }
   }
   return retVal;
}

इसके बजाय एक आस्थगित गणना बनाने के लिए उपज वापसी सिंटैक्स का उपयोग करें ।

public IEnumerable<Foo> GetEnumerationOfFoo()
{
   //no need to create an extra list
   //var retVal=new List<Foo>();
   foreach(var foo in _myPrivateFooList)
   {
      if(foo.DistinguishingValue == check)
      {
         //yield the match compiler handles the complexity
         yield return foo;
      }
   }
   //no need for returning a list
   //return retVal;
}

अब गणना तब तक नहीं होगी जब तक आप इस पर टालस्ट या इटरेट नहीं करेंगे। और यह केवल जरूरत के रूप में होता है (यहां फाइबॉनासी की गणना है जिसमें स्टैक अतिप्रवाह समस्या नहीं है)

/**
Returns an IEnumerable of fibonacci sequence
**/
public IEnumerable<int> Fibonacci()
{
  int first, second = 1;
  yield return first;
  yield return second;
  //the 46th fibonacci number is the largest that
  //can be represented in 32 bits. 
  for (int i = 3; i < 47; i++)
  {
    int retVal = first+second;
    first=second;
    second=retVal;
    yield return retVal;
  }
}

फिबोनाची फ़ंक्शन पर एक फ़ॉर्चेक का प्रदर्शन 46 का अनुक्रम लौटाएगा। यदि आप 30 वां चाहते हैं कि सभी की गणना की जाएगी

var thirtiethFib=Fibonacci().Skip(29).Take(1);

जहां हमें बहुत मज़ा आता है लैम्बडा एक्सप्रेशंस के लिए भाषा में समर्थन (IQueryable और IQueryProvider कंस्ट्रक्शन के साथ संयुक्त है, यह विभिन्न डेटा सेटों के खिलाफ प्रश्नों की कार्यात्मक संरचना के लिए अनुमति देता है, IQueryProvider पास की व्याख्या करने के लिए जिम्मेदार है। भाव और स्रोत के मूल निर्माण का उपयोग करके एक क्वेरी बनाना और निष्पादित करना)। मैं यहाँ पर निट्टी के बारे में नहीं बताऊंगा, लेकिन ब्लॉग पोस्ट की एक श्रृंखला है जिसमें दिखाया गया है कि कैसे SQL Query Ltd. बनाया जाए

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


13

लेकिन मैं कोड को कम और कम पठनीय देख सकता हूं

देखने वाले की नजर में पठनीयता होती है। कुछ लोग कह सकते हैं

var common = list1.Intersect(list2);

पूरी तरह से पठनीय है; दूसरों का कहना है कि यह अपारदर्शी है, और पसंद करेंगे

List<int> common = new List<int>();
for(int i1 = 0; i1 < list1.Count; i1++)
{
    for(int i2 = 0; i2 < list2.Count; i2++)
    {
        if (list1[i1] == list2[i2])
        {
            common.Add(i1);
            break;
        }
    }
}

यह स्पष्ट करने के रूप में कि क्या किया जा रहा है। हम आपको यह नहीं बता सकते हैं कि आपको क्या पढ़ने योग्य है। लेकिन आप मेरे द्वारा बनाए गए उदाहरणों में मेरे कुछ पूर्वाग्रह का पता लगाने में सक्षम हो सकते हैं ...


28
ईमानदारी से कहूंगा कि लिनक उद्देश्य को अधिक पठनीय बनाता है जबकि लूप तंत्र को उद्देश्यपूर्ण रूप से अधिक पठनीय बनाता है।
जे.के.

16
मैं उतनी ही तेजी से भाग सकता हूं जितना कोई मुझसे हो सकता है, जो मुझे बताता है कि फॉर-फॉर-इफ़ेक्ट, इंटरसेक्ट वर्जन की तुलना में अधिक पठनीय है।
कोनामनमन 12

3
@ कोनामिमान - यह इस बात पर निर्भर करेगा कि कोई व्यक्ति "पठनीयता" के बारे में क्या सोचता है। jk। की टिप्पणी इसे पूरी तरह दर्शाती है। लूप इस अर्थ में अधिक पठनीय है कि आप आसानी से देख सकते हैं कि इसका अंतिम परिणाम कैसे मिल रहा है, जबकि LINQ अधिक पठनीय है कि अंतिम परिणाम क्या होना चाहिए।
शौना

2
यही कारण है कि लूप कार्यान्वयन में चला जाता है, और फिर आप हर जगह इंट्रक्ट का उपयोग करते हैं।
आर। मार्टिनो फर्नांडीस

8
@ शऊना: कई अन्य काम करने वाली विधि के लिए फॉर-लूप संस्करण की कल्पना करें; यह एक गड़बड़ है। तो, स्वाभाविक रूप से, आप इसे अपनी विधि में विभाजित करते हैं। पठनीयता-वार, यह IEnumerable <T>। Inectect के समान है, लेकिन अब आपने फ्रेमवर्क कार्यक्षमता को दोहराया है और बनाए रखने के लिए अधिक कोड पेश किया है। केवल बहाना यह है कि आपको व्यवहारिक कारणों के लिए एक कस्टम कार्यान्वयन की आवश्यकता है, लेकिन हम केवल यहां पठनीयता के बारे में बात कर रहे हैं।
मिसको

7

LINQ के बीच का अंतर और foreachवास्तव में दो अलग-अलग प्रोग्रामिंग शैलियों को उबालता है: अनिवार्य और घोषणात्मक।

  • अभेद्य: इस शैली में आप कंप्यूटर से कहते हैं "यह करो ... अब यह करो ... अब यह करो अब यह करो"। आप इसे एक समय में एक कदम एक कार्यक्रम खिलाते हैं।

  • घोषणापत्र: इस शैली में आप कंप्यूटर को बताते हैं कि आप क्या परिणाम चाहते हैं और यह पता लगाने दें कि वहां कैसे पहुंचा जाए।

इन दो शैलियों का एक क्लासिक उदाहरण एसक्यूएल के साथ विधानसभा कोड (या सी) की तुलना कर रहा है। विधानसभा में आप एक बार में निर्देश (शाब्दिक) देते हैं। SQL में आप डेटा को एक साथ कैसे शामिल करते हैं और आप उस डेटा से क्या परिणाम चाहते हैं, इसे व्यक्त करते हैं।

घोषणात्मक प्रोग्रामिंग का एक अच्छा साइड-इफेक्ट यह है कि यह थोड़ा उच्च स्तर का हो जाता है। यह आपके प्लेटफ़ॉर्म को बदलने के लिए आपके बिना प्लेटफ़ॉर्म को विकसित करने की अनुमति देता है। उदाहरण के लिए:

var foo = bar.Distinct();

यहाँ क्या हो रहा है? क्या डिस्टिंक्ट एक कोर का उपयोग कर रहा है? दो? पचास? हम नहीं जानते और हमें परवाह नहीं है। .NET देवता इसे किसी भी समय फिर से लिख सकते हैं, जब तक यह एक ही उद्देश्य के लिए जारी रहता है, कोड अपडेट के बाद हमारा कोड केवल जादुई रूप से तेज़ हो सकता है।

यह कार्यात्मक प्रोग्रामिंग की शक्ति है। और इसका कारण यह है कि आप क्लोजर, एफ # और सी # (एक कार्यात्मक प्रोग्रामिंग मानसिकता के साथ लिखित) जैसी भाषाओं में उस कोड को अक्सर मिलेंगे, जो अनिवार्य समकक्षों की तुलना में 3x-10x छोटा है।

अंत में मुझे घोषणात्मक शैली पसंद है क्योंकि सी # में ज्यादातर यह मुझे कोड लिखने की अनुमति देता है जो डेटा को म्यूट नहीं करता है। उपरोक्त उदाहरण में, Distinct()बार नहीं बदलता है, यह डेटा की एक नई प्रति लौटाता है। इसका मतलब यह है कि जो कुछ भी बार है, और यह कभी भी कहां से आया है, यह अचानक नहीं बदला।

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


2
LINQ प्रसंस्करण तब तक के लिए स्थगित कर दिया जाता है जब तक आप वास्तव में उस पर पुनरावृति नहीं करते। var foo = bar.Distinct()अनिवार्य रूप से IEnumerator<T>जब तक आप कॉल .ToList()या नहीं करते हैं .ToArray()। यह एक महत्वपूर्ण अंतर है क्योंकि अगर आपको इस बारे में जानकारी नहीं है कि इससे बग को समझना मुश्किल हो सकता है।
बेरिन लोरिट्श

-5

क्या टीम के अन्य डेवलपर्स LINQ पढ़ सकते हैं?

यदि नहीं तो इसका उपयोग न करें या दो चीजों में से एक होगा:

  1. आपका कोड अप्राप्य रहेगा
  2. आप अपने सभी कोड और उस पर निर्भर रहने वाले सभी चीज़ों को बनाए रखने के साथ फंस जाएंगे

प्रत्येक लूप के लिए एक सूची के माध्यम से पुनरावृत्ति के लिए एकदम सही है, लेकिन अगर आप क्या करना है तो एक का उपयोग न करें।


11
हम्म, मैं सराहना करता हूं कि एक एकल परियोजना के लिए यह उत्तर हो सकता है, लेकिन मध्यम से दीर्घकालिक अवधि के लिए आपको अपने कर्मचारियों को प्रशिक्षित करना चाहिए, अन्यथा आपके पास कोड समझ के निचले भाग में दौड़ है जो एक अच्छे विचार की तरह नहीं है।
जे.के.

21
वास्तव में, एक तीसरी चीज है जो हो सकती है: अन्य डेवलपर्स प्रयास की एक छोटी राशि डाल सकते हैं और वास्तव में कुछ नया और उपयोगी सीख सकते हैं। यह अनसुना नहीं है।
एरिक किंग

6
@InvertedLlama अगर मैं एक ऐसी कंपनी में था जहाँ डेवलपर्स को नई भाषा अवधारणाओं को समझने के लिए औपचारिक प्रशिक्षण की आवश्यकता होती है तो मैं एक नई कंपनी खोजने के बारे में सोचूंगा।
व्याट बार्नेट

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

7
यह पहले से ही काफी डाउनवोट है, इसलिए मैं इससे नहीं जुड़ूंगा, लेकिन अज्ञानी / अक्षम सहकर्मियों का समर्थन करने वाला तर्क कभी भी मान्य नहीं होता है।
स्टीवन एवर्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.