2011-06-30 24 views
9

मैं एक साधारण Moneydecimal से एक अंतर्निहित कलाकारों के साथ प्रकार है:अप्रत्याशित प्रभाव

static class MoneyExtensions 
{ 
    public static Money Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, Money> selector) 
    { 
     return source.Select(x => (decimal)selector(x)).Sum(); 
    } 
} 
:

struct Money 
{ 
    decimal innerValue; 
    public static implicit operator Money(decimal value) 
    { 
     return new Money { innerValue = value }; 
    } 
    public static explicit operator decimal(Money value) 
    { 
     return value.innerValue; 
    } 

    public static Money Parse(string s) 
    { 
     return decimal.Parse(s); 
    } 
} 

और मैं उन मूल्यों पर संचालित करने के लिए एक Sum() अधिभार परिभाषित

जो मैंने अपेक्षा नहीं की थी वह मौजूदा Sum() एक्सटेंशन विधियों में हस्तक्षेप करने के लिए इस विस्तार विधि के लिए थी:

var source = new[] { "2" }; 
Money thisWorks = source.Sum(x => Money.Parse(x)); 
int thisWorksToo = source.Sum(new Func<string, int>(x => int.Parse(x))); 
int thisDoesNot = source.Sum(x => int.Parse(x)); 

त्रुटि यह है कि "आसानी से प्रकार 'मनी' को 'int' में परिवर्तित नहीं किया जा सकता है। एक स्पष्ट रूपांतरण मौजूद है (यदि आप एक डाली याद कर रहे हैं?) "। यह सही है कि संकलक एक अधिभार सटीक मेल है कि हल करने से अधिक int => decimal => Money अंतर्निहित रूपांतरण के पक्ष में है?

+0

मुझे सटीक मिलान – Jodrell

+0

सटीक मिलान याद आ रहा है सिस्टम में 'Sum() '' int') 'int' अधिभार। – dahlbyk

+0

क्या आप एक पूरा उदाहरण प्रदान कर सकते हैं जो संकलन-त्रुटि उत्पन्न करता है? आपने अपनी 'उपयोग' घोषणाएं नहीं दिखाईं हैं, जो इस स्थिति में बहुत महत्वपूर्ण हैं। –

उत्तर

8

सी # 4.0 विशिष्टता, खंड 7.6.5.2 से: विस्तार तरीके उपलब्ध अधिक

पूर्ववर्ती नियमों का मतलब है कि उदाहरण के तरीकों विस्तार तरीकों से प्राथमिकता दी जाती है कि विस्तार भीतरी नाम स्थान घोषणाओं में उपलब्ध तरीकों ले पूर्वता बाहरी नेमस्पेस घोषणाओं में, और नामस्थान में सीधे घोषित विस्तार विधियों को उसी नामस्थान में आयात किए गए विस्तार विधियों पर प्राथमिकता लेती है, जिसमें नामस्थान निर्देश

शायद, यह आपके मनी सम एक्सटेंशन विधि को लिंक से लोगों पर प्राथमिकता लेने का कारण बन रहा है - यही कारण है कि आपको "संदिग्ध विधि कॉल" त्रुटि नहीं मिलती है।

+0

तो अगर मैं अपनी 'Sum()' विधि को एक अलग नेमस्पेस में ले जाऊं तो इसे काम करना चाहिए? – dahlbyk

+0

@dahlbyk, हाँ यह काम करता है मैंने कोशिश की, अच्छा जवाब, + 1 – Jodrell

+0

@dahlbyk: हाँ - यह विस्तार करना चाहिए यदि विस्तार विधि वर्ग का रूट नेमस्पेस आपके टेस्ट कोड को निष्पादित करने से अलग है। – RobSiklos

-1

क्योंकि आप स्पष्ट रूप से प्रकार int रूप thisDoesNot की घोषणा कर रहे हैं यह है। आप तो specification से

void Main() 
{ 
    var source = new[] { "2" }; 
    Money thisWorks = source.Sum(x => Money.Parse(x)); 
    int thisWorksToo = source.Sum(new Func<string, int>(x => int.Parse(x))); 
    var thisDoesNot = source.Sum(x => int.Parse(x)); 

    Console.Write(thisDoesNot.GetType()); 
} 

: निहित घोषणा उपयोग करें, यह ठीक काम करता है

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

+0

का हिस्सा हैं, यह संकलित करता है, लेकिन 'thisDoesNot' में' int' के बजाय 'मनी' टाइप किया गया है।वास्तविक परिदृश्य में, मेरे पास 'मनी प्राइस' और 'इंट क्वांटिटी' वाले आइटमों की एक गाड़ी है - 'मात्रा' लौटने पर 'Sum()' को 'इंटी' वापस करने में विफल रहता है। – dahlbyk

+0

ओह, मैंने सोचा था कि आप इसे पैसा टाइप करना चाहते थे। मैं देखता हूं ... – scottm

+0

विस्तार विनिर्देशों के आसपास होने से पहले यह विनिर्देश वीएस 2003 के लिए है। – RobSiklos

2

रॉब सिकलोस के शोध के बाद, (कृपया अनुसंधान को वोट दें) एक अलग नामस्थान में एक्सटेंशन को इस समस्या को हल करता है। मुझे इसे विस्तार के लिए दिशानिर्देशों में से एक के रूप में याद किया जाता है।

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Extensions; 

namespace Currency 
{ 
    struct Money 
    {   
     decimal innerValue; 
     public static implicit operator Money(decimal value) 
     { 
      return new Money { innerValue = value }; 
     } 
     public static explicit operator decimal(Money value) 
     { 
      return value.innerValue; 
     } 
     public static Money Parse(string s) 
     { 
     return decimal.Parse(s); 
     } 
    } 

    class Program 
    { 
     static void Main() 
     { 
      var source = new[] { "2" }; 
      Money thisWorks = source.Sum(x => Money.Parse(x)); 
      int thisWorksToo = 
       source.Sum(new Func<string, int>(x => int.Parse(x)));  
      int thisWorksTooNow = source.Sum(x => int.Parse(x)); 

     } 
    } 
} 
namespace Extensions 
{ 
    static class IEnumerableTExtensions 
    { 
     public static Currency.Money Sum<TSource>(
             this IEnumerable<TSource> source, 
             Func<TSource, Currency.Money> selector) 
     { 
      return source.Select(x => (decimal)selector(x)).Sum(); 
     } 
    } 
} 
संबंधित मुद्दे