2012-06-27 11 views
12

तो, IEnumerable के लिए एक बहुत ही आम विस्तार विधि, भागो:क्यों C# के अधिभार रिज़ॉल्यूशन Func <T,T> और एक्शन <T> के बीच काम नहीं करता है?

public static IEnumerable<T> Run<T>(this IEnumerable<T> source, Action<T> action) 
{ 
    foreach (var item in source) 
    { 
     action(item); 
     yield return item; 
    } 
} 

जब मैं उपयोग करने के लिए उस के साथ, उदाहरण के लिए प्रयास करते हैं, DbSet.Add:

invoice.Items.Run(db.InvoiceItems.Add); 
// NB: Add method signature is 
// public T Add(T item) { ... } 

... संकलक शिकायत है कि इसमें गलत रिटर्न प्रकार है, क्योंकि यह शून्य विधि की अपेक्षा कर रहा है। तो, कि कार्रवाई के बजाय एक समारोह लेता भागो के लिए एक अधिभार जोड़ें:

public static IEnumerable<T> Run<T>(this IEnumerable<T> source, Func<T, T> action) 
{ 
    return source.Select(action).ToList().AsEnumerable(); 
} 

और अब संकलक शिकायत है कि "कॉल निम्न विधियों के बीच अस्पष्ट है ..."

तो मेरे सवाल है, रन विधि का एक्शन ओवरलोड अस्पष्टता का कारण बन सकता है जब यह विधि समूह के लिए मान्य नहीं है? सही तरीके से

+0

'db.InvoiceItems.Add' का हस्ताक्षर क्या है? – leppie

+0

सार्वजनिक टी जोड़ें (टी आइटम) {...} –

+0

संक्षिप्त उत्तर: 'x => x.ToString() 'क्या यह लैम्ब्डा बस ToString का आह्वान कर सकता है या ToString का आह्वान कर सकता है और इसका परिणाम वापस कर सकता है?दूसरे शब्दों में, क्या यह लैम्ब्डा को फनक या एक्शन के रूप में संभाला जाना चाहिए? संकलक आपके लिए यह निर्णय नहीं ले सकता है इसलिए एक त्रुटि। – Polity

उत्तर

5

यह this question के उत्तर में एरिक और जॉन द्वारा पहले ही समझाया गया है। लंबी कहानी छोटी - इस तरह सी # कंपाइलर काम करता है; ठीक है, पर निर्णय करते समय प्रतिनिधि यह अधिभार संकल्प है, जो प्रकार वापसी खाता में नहीं ले करता है का इस्तेमाल करने के लिए परिवर्तित किया जाएगा विधि समूह रूपांतरण के साथ काम:

सिद्धांत यहाँ जाता है कि निर्धारित करने विधि समूह परिवर्तनीयता एक विधि का चयन की आवश्यकता है ओवरलोड रिज़ॉल्यूशन का उपयोग कर एक विधि समूह से, और ओवरलोड रिज़ॉल्यूशन रिटर्न प्रकारों पर विचार नहीं करता है।

अपने उदाहरण संकलक में दोनों Action<T> और Func<T, T>सबसे अच्छा मैचAdd के लिए के रूप में देखता है। यह दो संभावित विकल्पों को जोड़ता है, और चूंकि इसे एक की आवश्यकता होती है - उचित त्रुटि जारी की जाती है।

0

कोशिश अधिभार:

public static IEnumerable<TDest> Run<TSource, TDest>(this IEnumerable<TSource> source, 
    Func<TSource, TDest> action) 
{ 
return source.Select(action).ToList(); 
} 
+0

थोड़ा सा अंतर नहीं बनाता है। –

+0

आपको क्वेरी को निष्पादित करने से बचने के लिए यहां क्लिक करें। –

+0

@SteveB विधि का नाम चलाया गया है, लेकिन LazyRun –

0

मैं उत्तर नहीं दे सकता क्यों लेकिन अस्पष्टता को हल करने आप स्पष्ट रूप से अपने कार्य डाली कर सकते हैं:

invoice.Items.Run((Func<T,T>)db.InvoiceItems.Add); 

या एक लैम्ब्डा का उपयोग

invoice.Items.Run(x => db.InvoiceItems.Add(x)); 
0

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

// with T replaced with the actual type: 
invoice.Items.Run((Func<T, T>)db.InvoiceItems.Add); 
invoice.Items.Run(new Func<T, T>(db.InvoiceItems.Add)); 

आपको इन तरीकों की आवश्यकता क्यों है? इसमें क्या गड़बड़ है:

foreach (var item in invoice.Items) 
    db.InvoiceItems.Add(item); 

इस की पठनीयता बहुत बेहतर है। जब तक आपके पास Run विधि की आवश्यकता के लिए कोई अच्छा कारण न हो, तो मैं इसका उपयोग करने के खिलाफ अनुशंसा करता हूं। मैंने जो देखा है, उससे कम से कम Action<T> अधिभार के लिए ऐसा कोई कारण नहीं है।

+0

रन एक सामान्य कार्यात्मक-शैली घोषणात्मक ऑपरेशन है, और मैं असहमत हूं कि foreach फॉर्म अधिक पठनीय है। इसके अलावा, एक बार जब आप ब्रेसिज़ डालते हैं, तो इसकी बजाय चार लाइनें होती हैं। मैं इसे आधा दर्जन बाल संग्रह के लिए कर रहा हूं; प्रत्येक के बीच एक खाली रेखा में जोड़ें और कोड की ~ 30 पंक्तियां, जो युक्त विधि को बहुत लंबा बनाती है, इसलिए मैं प्रत्येक foreach को एक अलग विधि में दोबारा दोहराता हूं। फिर मैं चीजों को कम रखने के लिए उस विधि को दोबारा दोहराता हूं, और हे पस्टो, मुझे वैसे भी एक रन विधि मिल गई है। –

+1

@MarkRendle आपका 'रन() 'बहुत कार्यात्मक नहीं है। कार्यात्मक प्रोग्रामिंग का बड़ा हिस्सा उन कार्यों को लिख रहा है जिनके दुष्प्रभाव नहीं हैं। और 'रन() 'उपयोगी * केवल * दुष्प्रभावों के लिए है। मैं इस पर टिम से सहमत हूं: 'foreach' अधिक पठनीय है और' रन() 'जैसी विधियों का उपयोग करना बहुत अच्छा अभ्यास नहीं है। – svick

+0

@svick मैं सम्मान से असहमत हूं। –

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