2010-10-01 8 views
19

जब एक List<string> की तरह कुछ के साथ काम कर आप निम्नलिखित लिख सकते हैं:यदि उपलब्ध हो तो सी # विधि समूह का उपयोग करने के कोई लाभ हैं?

list.ForEach(x => Console.WriteLine(x)); 

या आप एक विधि समूह उपयोग कर सकते हैं एक ही आपरेशन करने के लिए:

list.ForEach(Console.WriteLine); 

मैं क्योंकि कोड की दूसरी पंक्ति पसंद करते हैं यह मेरे लिए क्लीनर दिखता है, लेकिन क्या इसका कोई फायदा है?

+3

खैर, ReSharper दूसरे संस्करण की सिफारिश की। तो यह सही होना चाहिए ... –

+4

"कोई व्यक्ति समझता है कि सही है" वास्तव में * क्यों * की व्याख्या नहीं है। यह सही हो सकता है। यह सबसे अच्छा जवाब हो सकता है। लेकिन वह "क्यों" के सवाल का जवाब नहीं देता है। – WernerCD

उत्तर

23

ठीक है, देखते हैं और देखें कि क्या होता है।

static void MethodGroup() 
{ 
    new List<string>().ForEach(Console.WriteLine); 
} 

static void LambdaExpression() 
{ 
    new List<string>().ForEach(x => Console.WriteLine(x)); 
} 

यह निम्नलिखित आईएल में संकलित हो जाता है।

.method private hidebysig static void MethodGroup() cil managed 
{ 
    .maxstack 8 
    L_0000: newobj instance void [mscorlib]System.Collections.Generic.List`1<string>::.ctor() 
    L_0005: ldnull 
    L_0006: ldftn void [mscorlib]System.Console::WriteLine(string) 
    L_000c: newobj instance void [mscorlib]System.Action`1<string>::.ctor(object, native int) 
    L_0011: call instance void [mscorlib]System.Collections.Generic.List`1<string>::ForEach(class [mscorlib]System.Action`1<!0>) 
    L_0016: ret 
} 

.method private hidebysig static void LambdaExpression() cil managed 
{ 
    .maxstack 8 
    L_0000: newobj instance void [mscorlib]System.Collections.Generic.List`1<string>::.ctor() 
    L_0005: ldsfld class [mscorlib]System.Action`1<string> Sandbox.Program::CS$<>9__CachedAnonymousMethodDelegate1 
    L_000a: brtrue.s L_001d 
    L_000c: ldnull 
    L_000d: ldftn void Sandbox.Program::<LambdaExpression>b__0(string) 
    L_0013: newobj instance void [mscorlib]System.Action`1<string>::.ctor(object, native int) 
    L_0018: stsfld class [mscorlib]System.Action`1<string> Sandbox.Program::CS$<>9__CachedAnonymousMethodDelegate1 
    L_001d: ldsfld class [mscorlib]System.Action`1<string> Sandbox.Program::CS$<>9__CachedAnonymousMethodDelegate1 
    L_0022: call instance void [mscorlib]System.Collections.Generic.List`1<string>::ForEach(class [mscorlib]System.Action`1<!0>) 
    L_0027: ret 
} 

सूचना कैसे विधि समूह दृष्टिकोण एक समय का उपयोग के लिए एक Action<T> प्रतिनिधि और लैम्ब्डा अभिव्यक्ति दृष्टिकोण बनाता है एक छिपा हुआ गुमनाम प्रतिनिधि क्षेत्र बनाता है और यदि आवश्यक हो तो इसके बारे में एक इनलाइन प्रारंभ करता है। IL_000a पर brtrue निर्देश पर ध्यान दें।

+0

कैसे क्या मैं संकलित आईएल देख सकता हूं? –

+0

@ एमएच .: आईएलडीएएसएम या परावर्तक का प्रयोग करें। –

+0

@ एम.एच. आप संकलित आईएल देखने के लिए LINQPad का उपयोग कर सकते हैं – mbx

3

हां; पहला वास्तव में एक अनावश्यक अतिरिक्त, अंतरिम कॉल होने का कारण बन सकता है; x को Console.WriteLine(x); पर कॉल करने वाली विधि में गुजरने के लिए आपको पहले ऐसा करने की आवश्यकता नहीं है क्योंकि कंसोल। राइटलाइन पहले से ही एक विधि है जो हस्ताक्षर से मेल खाती है जो फॉरएच की तलाश में है।

0

व्यक्तिगत रूप से मैं दूसरा भी पसंद करता हूं क्योंकि यह डीबग करने में कम भ्रमित है, लेकिन इस मामले में मुझे लगता है कि यह सिर्फ शैली का मामला है क्योंकि वे दोनों एक ही काम कर रहे हैं।

0

उन लोगों के लिए अधिक सुखद बनाने के अलावा कोई ठोस लाभ नहीं है जो विधि समूहों को पसंद करते हैं, और उन्हें नापसंद करने वाले लोगों को परेशान करते हैं [यह आपको खुश करना चाहिए।] इसके अलावा, यह आपके कोड को पहले के कंपाइलर्स के साथ असंगत बनाता है।

-Oisin

+0

कौन से कंपाइलर्स दूसरे को स्वीकार करते हैं और पहले नहीं? –

7

मुझे विश्वास है कि एक लाभ है। पहले मामले में आप अज्ञात विधि बना रहे हैं जो Console.Writeline(string) फ़ंक्शन को कॉल करता है जबकि अन्य मामले में आप मौजूदा फ़ंक्शन का संदर्भ दे रहे हैं।

+3

हाँ, यह भी मेरी भावना थी। मुझे कल्पना है कि यह संभव है कि ऑप्टिमाइज़र इसे पहचान सके और अतिरिक्त, अनियंत्रित कॉल को बाहर कर सके, लेकिन जब इसे 'बेहतर' तरीका लिखना वास्तव में आसान होता है, तो ऐसा करने के लिए यह समझ में आता है, आईएमओ। मैंने इस विषय के बारे में एक ब्लॉग पोस्ट लिखा है (अनावश्यक रूप से लैम्ब्डा अभिव्यक्तियों का उपयोग इस तरह करते हैं: http://www.andrewbarber.com/post/When-to-Avoid-Lambda-Expressions-or-What-Aonymous-Methods.aspx) –

7

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

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

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

8

जैसा कि अन्य ने उल्लेख किया है, लैम्ब्डा द्वारा प्रेरित संकेत की एक अतिरिक्त अनावश्यक परत है। हालांकि, सूक्ष्म भाषा मतभेद भी हैं। उदाहरण के लिए, सी # 3 जेनेरिक टाइप अनुमान M(F) पर M(x=>F(x)) पर अलग-अलग प्रकार के काम करता है जब रिटर्न टाइप अनुमान प्रदर्शन करने का प्रयास किया जाता है।

जानकारी के लिए देखें:

http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx

और अनुवर्ती:

http://blogs.msdn.com/b/ericlippert/archive/2008/05/28/method-type-inference-changes-part-zero.aspx

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