2011-06-28 26 views
14

यह दो विस्तार के तरीकों का एक सरल उदाहरण overloads हैवैकल्पिक प्रतिनिधियों

public static class Extended 
{ 
    public static IEnumerable<int> Even(this List<int> numbers) 
    { 
     return numbers.Where(num=> num % 2 == 0); 
    } 

    public static IEnumerable<int> Even(this List<int> numbers, Predicate<int> predicate) 
    { 
     return numbers.Where(num=> num % 2 == 0 && predicate(num)); 
    } 
} 

मैं उन्हें एक में विलय करने के लिए, एक प्रतिनिधि की स्थापना वैकल्पिक होने के लिए द्वारा सक्षम होने के लिए करना चाहते हैं:

public static class Extended 
{ 
    public static IEnumerable<int> Even(this List<int> numbers, Predicate<in> predicate = alwaysTrue) 
    { 
     return numbers.Where(num=> num % 2 == 0 && predicate(num)); 
    } 

    public static bool alwaysTrue(int a) { return true; } 
} 

हालांकि, संकलक एक त्रुटि फेंकता है:

Default parameter value for 'predicate' must be a compile-time constant

मैं नहीं दिख रहा है कि मेरे alwaysTrue समारोह स्थिर नहीं है, लेकिन हे, संकलक kno ws बेहतर :)

क्या प्रतिनिधि पैरामीटर वैकल्पिक बनाने का कोई तरीका है?

+0

बहुत दिलचस्प सवाल +1 –

उत्तर

19

यह स्थिर नहीं है क्योंकि आपने एक विधि समूह से एक प्रतिनिधि बनाया है ... यह संकलन-समय स्थिर नहीं है जब तक सी # भाषा का संबंध नहीं है।

आप null का अर्थ कोस कोई आपत्ति नहीं है थोड़ा आप इस्तेमाल कर सकते हैं:

private static readonly Predicate<int> AlwaysTrue = ignored => true; 

public static List<int> Even(this List<int> numbers, 
          Predicate<int> predicate = null) 
{ 
    predicate = predicate ?? AlwaysTrue; 
    return numbers.Where(num=> num % 2 == 0 && predicate(num)); 
} 

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

+0

कभी कभी मैं चाहता हूँ कई होगा इतने पर स्वीकार करता है। सभी उत्तरों सही हैं, हालांकि जॉन का जवाब मेरे लिए सबसे अधिक लाभदायक लगता है क्योंकि उन्होंने मुझे जाने और विधि समूहों के बारे में पढ़ने के लिए वास्तव में कुछ सीखने के लिए पढ़ा जो मुझे नहीं पता था। –

+0

आप क्यों कहते हैं कि 'AlwaysTrue' नामित विधि से अज्ञात विधि के रूप में थोड़ा अधिक कुशल है? मैं आपके * विधि समूह रूपांतरण * भाग को समझ नहीं रहा हूं। 'predicate = predicate ?? AlwaysTrue; 'जब भी हमेशा' एक विधि है, तब भी लिखा जा सकता है, और उस स्थिति में जहां 'predicate' एक शून्य है, विधि कहा जाता है। फिर भी प्रतिनिधि केवल एक बार सही बनाया गया है? तो अब यह नाम विधि बनाम अज्ञात विधि के बारे में है। क्या उत्तरार्द्ध अधिक प्रदर्शनकारी है? – nawfal

+0

@nawfal: किसी क्षेत्र का उपयोग करने का अर्थ है कि जब आप 'यहां तक ​​कि' कॉल करते हैं, तो यह एक नया प्रतिनिधि उदाहरण नहीं बनाता है, क्योंकि यह फ़ील्ड से किसी का पुन: उपयोग करता है। विधि समूह रूपांतरण के साथ, यह मानते हुए कि 'predicate' शून्य है, जो प्रत्येक कॉल पर एक नया प्रतिनिधि उदाहरण बनाएगा - प्रतिनिधि को कैश नहीं किया जाता है। –

1
public static List<int> Even(this List<int> numbers, Predicate<in> predicate = null) 
{ 
    return numbers.Where(num=> num % 2 == 0 && (predicate == null || predicate(num))); 
} 
+0

दोह, @ जोन द्वारा इसे पीटा गया! –

3

आप क्या करना है यह +०१२३०५६४७८ होने की अनुमति है, और फिर के रूप में हमेशा सही के रूप में व्यवहार करें।

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

public static List<int> Even(this List<int> numbers, Predicate<int> predicate = null) 
{ 
    if (predicate == null) 
     return numbers.Where(num=> num % 2 == 0).ToList(); 
    else 
     return numbers.Where(num=> num % 2 == 0 && predicate(num)).ToList(); 
} 

या, एक डमी कार्यान्वयन प्रदान करते हैं:

public static List<int> Even(this List<int> numbers, Predicate<int> predicate = null) 
{ 
    predicate = predicate ?? new Predicate<int>(alwaysTrue); 
    return numbers.Where(num=> num % 2 == 0 && predicate(num)).ToList(); 
} 

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

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

दूसरे शब्दों में, इस कॉल:

var even = list.Even(); 

है जैसे कि यह इस तरह लिखा गया था दिखेगा:

var even = list.Even(null); 

आप अब विधि बदलते हैं, एक बार फिर अतिभारित किया जा सकता है अगर ऊपर कॉल पुन: संकलित नहीं किया गया है, तो यह हमेशा उस प्रतिनिधि के लिए एक प्रतिनिधि को कॉल करेगा, केवल उस पैरामीटर के लिए null प्रदान करेगा।

2

आप एक null -default मूल्य इस्तेमाल कर सकते हैं:

public static class Extended 
{ 
    public static IEnumerable<int> Even(this IEnumerable<int> numbers, 
             Predicate<int> predicate = null) 
    { 
     if (predicate==null) 
     { 
      predicate = i=>true; 
     } 

     return numbers.Where(num => num % 2 == 0 && predicate(num)); 
    } 
} 
संबंधित मुद्दे