2009-08-26 19 views
12

के भीतर गहरी संपत्ति को संशोधित करें और अपडेट करें को किसी ऑब्जेक्ट के एक या अधिक गुणों पर डेटा सदस्य 5 या 6 स्तर गहराई के लिए आवश्यक मान पर विचार करें।LINQ के साथ नेस्टेड foreach को बदलना;

उप-संग्रह हैं जिन्हें संपत्ति & संशोधन की आवश्यकता वाले संपत्ति को पाने के लिए पुनरावृत्त करने की आवश्यकता है।

यहां हम एक ऐसी विधि को बुला रहे हैं जो कर्मचारी के सड़क पते को साफ़ करता है। हम छोरों के भीतर डेटा बदल रहे हैं के बाद से, वर्तमान कार्यान्वयन एक for पाश की जरूरत अपवाद को रोकने के लिए:

करने के लिए "someVariable" आवंटित नहीं कर सकता क्योंकि यह 'foreach यात्रा चर'

यहाँ है नेस्टेड foreach और for के साथ वर्तमान एल्गोरिदम (obfuscated)।

foreach (var emp in company.internalData.Emps) 
{ 
    foreach (var addr in emp.privateData.Addresses) 
    { 
     int numberAddresses = addr.Items.Length; 

     for (int i = 0; i < numberAddresses; i++) 
     { 
      //transform this street address via a static method 
      if (addr.Items[i].Type =="StreetAddress") 
       addr.Items[i].Text = CleanStreetAddressLine(addr.Items[i].Text); 
     } 
    } 
} 

प्रश्न: इस एल्गोरिथ्म LINQ का उपयोग कर reimplemented जा सकता है? मूल संग्रह के लिए उस स्थिर विधि कॉल द्वारा अपना डेटा बदलना आवश्यक है।

अद्यतन: मैं एक jQuery/चयनकर्ता प्रकार समाधान की दिशा में सोच/झुकाव सोच रहा था। मैंने इस सवाल को विशेष रूप से इस तरह से नहीं लिखा था। मुझे एहसास हुआ कि मैं उस विचार पर अधिक पहुंच रहा था (कोई दुष्प्रभाव नहीं)। सभी को धन्यवाद! यदि jQuery- जैसे चयनकर्ता को ऐसा करने का कोई तरीका है, तो कृपया इसे देखें!

उत्तर

11

LINQ वस्तुओं के सेट को संशोधित करने के लिए नहीं है। आप चयनित चयन पंक्तियों के मानों को संशोधित करने के लिए एक चयन एसक्यूएल कथन की अपेक्षा नहीं करेंगे, क्या आप? यह याद रखने में मदद करता है कि LINQ क्या है - भाषा एकीकृत प्राकृतिक क्वेरी। एक linq क्वेरी के भीतर वस्तुओं को संशोधित करना, आईएमएचओ, एक विरोधी पैटर्न है।

स्टेन आर का उत्तर फोरैच लूप का उपयोग करके एक बेहतर समाधान होगा, मुझे लगता है।

+0

धन्यवाद। तुम्हारा और मरदाद के जवाब कार्यात्मक रूप से समान थे, लेकिन मैंने तुम्हारा पहला देखा :) मुझे लगा कि यह कोड को फिर से टाइप करने के लिए व्यर्थ होगा, लेकिन मुझे लगा कि दुष्प्रभावों के बारे में बिंदु बनाना महत्वपूर्ण था –

+0

LINQ कार्यान्वयन के बावजूद SQL सर्वर नहीं है एसक्यूएल के लिए उस से अलग है .NET एक - आप अभी भी दोनों सेट (LINQ से SQL) और केवल C# LINQ के साथ गुणों को बदल सकते हैं। – ppumkin

18
foreach(var item in company.internalData.Emps 
         .SelectMany(emp => emp.privateData.Addresses) 
         .SelectMany(addr => addr.Items) 
         .Where(addr => addr.Type == "StreetAddress")) 
    item.Text = CleanStreetAddressLine(item.Text); 
+0

SelectMany नेस्टेड foreach से अधिक प्रदर्शन में सुधार होगा? – ManirajSS

+0

LINQ प्रदर्शन नगण्य है कि यह उत्तर कितना सुंदर है। (लेकिन नहीं ... LINQ बहुत तेज तेज है) – ppumkin

1

LINQ साइड इफेक्ट्स का विकल्प प्रदान नहीं करता है। लेकिन तुम कर सकते हो:

company.internalData.Emps.SelectMany(emp => emp.Addresses).SelectMany(addr => Addr.Items).ToList().ForEach(/*either make an anonymous method or refactor your side effect code out to a method on its own*/); 
12
var dirtyAddresses = company.internalData.Emps.SelectMany(x => x.privateData.Addresses) 
               .SelectMany(y => y.Items) 
               .Where(z => z.Type == "StreetAddress"); 

    foreach(var addr in dirtyAddresses) 
    addr.Text = CleanStreetAddressLine(addr.Text); 
0

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

इसे ध्यान में रखते

, क्या आप शायद चाहते हैं कुछ इस तरह है:

var addressItems = company.internalData.Emps.SelectMany(
    emp => emp.privateData.Addresses.SelectMany(
      addr => addr.Items 
    ) 
); 
foreach (var item in addressItems) 
{ 
    ... 
} 

लेकिन यदि आप आप वास्तव में क्या पूछा क्या करना चाहते हैं, तो इस दिशा में आप जाने की आवश्यकता होगी है:

var addressItems = company.internalData.Emps.SelectMany(
    emp => emp.privateData.Addresses.SelectMany(
      addr => addr.Items.Select(item => 
      { 
       // Do the stuff 
       return item; 
      }) 
    ) 
); 
10

I don't like mixing "query comprehension" syntax and dotted-method-call syntax एक ही कथन में।

मुझे क्वेरीकार्रवाई से अलग करने का विचार पसंद है। ये अर्थात् अलग हैं, इसलिए कोड में उन्हें अलग करना अक्सर समझ में आता है।

var addrItemQuery = from emp in company.internalData.Emps 
        from addr in emp.privateData.Addresses 
        from addrItem in addr.Items 
        where addrItem.Type == "StreetAddress" 
        select addrItem; 

foreach (var addrItem in addrItemQuery) 
{ 
    addrItem.Text = CleanStreetAddressLine(addrItem.Text); 
} 

आपके कोड के बारे में कुछ स्टाइल नोट; इन व्यक्तिगत कर रहे हैं, इसलिए मैं आप सहमत नहीं हो सकता है:

  • सामान्य तौर पर, मैं संक्षिप्त रूपों से बचने के (Emps, emp, addr)
  • असंगत नाम भ्रामक हैं (addr बनाम Addresses): एक चुनना और साथ चिपके रहते हैं यह
  • शब्द "संख्या" शब्दकोष है। यह या तो एक पहचान हो सकती है ("कैदी संख्या 378 कृपया आगे बढ़ें।") या एक गिनती ("उस क्षेत्र में भेड़ों की संख्या 12 है।")। चूंकि हम कोड में दोनों अवधारणाओं का बहुत उपयोग करते हैं, इसलिए यह स्पष्ट करने के लिए मूल्यवान है। मैं अक्सर पहले के लिए "इंडेक्स" और दूसरे के लिए "गिनती" का उपयोग करता हूं।
  • type फ़ील्ड होने के बाद एक स्ट्रिंग एक कोड गंध है। यदि आप इसे enum बना सकते हैं तो आपका कोड शायद बेहतर होगा।
+0

आपकी टिप्पणियों के लिए धन्यवाद जय। कोड वास्तविक परियोजना से प्रतिलिपि नहीं किया गया था, और सार्वजनिक खपत के लिए obfuscated था। –

+0

मैं इसे दूसरा करता हूं। अद्यतन से क्वेरी को अलग करना एक बहुत साफ और अधिक रखरखाव समाधान बनाता है। यह यहां सूचीबद्ध सभी "सभी में एक" लैम्ब्डा अभिव्यक्ति समाधान से कहीं बेहतर है। – SeeMoreGain

2

गंदा एक-लाइनर।

company.internalData.Emps.SelectMany(x => x.privateData.Addresses) 
    .SelectMany(x => x.Items) 
    .Where(x => x.Type == "StreetAddress") 
    .Select(x => { x.Text = CleanStreetAddressLine(x.Text); return x; }); 
0

, मैं पहले स्थानीय 'सूची' बनाने चर foreach पाश का उपयोग कर LINQ परिणाम अद्यतन करने के लिए और फिर foreach लूप का उपयोग कर अद्यतन प्रदर्शन करते हैं। मूल्य इस तरह से अद्यतन कर रहे हैं। यहां अधिक पढ़ें:

How to update value of LINQ results using FOREACH loop

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