2013-01-14 23 views
9

किसी भी तरह कोड का पालन VS2010 में संकलित नहीं है लेकिन परिवर्तन के बिना VS2012 में संकलित करता है। VS2010 में समस्याग्रस्त लाइनयह कोड वीएस -2010 में .NET 4.0 के साथ क्यों संकलित नहीं करता है?

names.Select(foo.GetName) 

त्रुटि CS1928 है: 'स्ट्रिंग []' 'चुनें' के लिए एक परिभाषा और सबसे अच्छा विस्तार विधि अधिभार 'System.Linq.Enumerable.Select < TSource, TResult शामिल नहीं है > (System.Collections.Generic.IEnumerable <TSource>, System.Func < TSource, TResult >) 'में कुछ ऐसी अमान्य तर्क हैं।

using System; 
using System.Linq; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main() 
     { 
      var foo = new Foo(); 
      var names = new[] {"Hello"}; 
      Console.WriteLine(string.Join(", ", names.Select(foo.GetName))); 
     } 
    } 

    public class Foo 
    { 
    } 

    static class Extensions 
    { 
     public static string GetName(this Foo foo, string name) 
     { 
      return name; 
     } 
    } 
} 

उत्तर

3

अपडेट किया गया उत्तर

मैं जाँच की है कि कोड स्निपेट names.Select(foo.GetName) वी.एस. 2012 में संकलित, और VS2010 पर संकलन नहीं करता है।

मुझे कारण पता नहीं है (सी # 5.0 या .NET 4.5 या नई एपीआई में नई सुविधा सटीक होने के लिए) जिसने इसे संभव बना दिया।

लेकिन त्रुटि

The type arguments for method 'System.Linq.Enumerable.Select<TSource,TResult>(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,TResult>)' cannot be inferred from the usage. Try specifying the type arguments explicitly. 

यह Enumerable.Select की तरह लगता है निम्न पैरामीटर प्राप्त करेगा और foo.GetName की वापसी प्रकार करने में सक्षम नहीं है।

प्रकार निर्दिष्ट करना, कोड संकलित होगा।

के बाद 3 विकल्प

1 कर रहे हैं। Func<string,string>

string.Join(", ", names.Select<string,string>(foo.GetName).ToArray()) 

2 कास्टिंग। Select खंड

string.Join(", ", names.Select((Func<string,string>)foo.GetName).ToArray()) 

3 में जेनेरिक पैरामीटर के रूप में निर्दिष्ट प्रकार। अज्ञात प्रतिनिधि में स्पष्ट रूप से कॉल फ़ंक्शन।

Console.WriteLine(string.Join(", ", names.Select(name => foo.GetName(name)))) 

लेकिन जैसे जॉन स्कीट टिप्पणी में बताया ऊपर एक नई विधि बनाकर किसी अन्य समारोह कॉल जोड़ देगा।

मूल जवाब

क्यों इस कोड .NET 4.0 के साथ VS2010 में संकलन नहीं करता है?

आप नाम पर पैरामीटर नहीं पारित कर रहे हैं। Func<T1,T2> के स्थान पर आप विधि का नाम पारित कर रहे हैं।


निम्नलिखित

Console.WriteLine(string.Join(", ", names.Select(name => foo.GetName(name)))) 
+3

खैर नहीं काफी। वे बराबर कोड नहीं कर रहे हैं काफी - अपने कोड एक नया तरीका है जो सिर्फ getName के प्रतिनिधियों, तो एक प्रतिनिधि है कि विधि का उपयोग कर बनाने के ... जबकि मूल एक प्रतिनिधि getName के लिए सीधे बात कर बन जाएगा पैदा करेगा। –

+0

@ जोनस्केट: लेकिन यह संकलन करने का एकमात्र तरीका है, है ना? जबकि विस्तार विधियां उदाहरण विधियों की तरह दिखती हैं, वे नहीं हैं और इस प्रकार हमेशा उनके जैसे उपयोग नहीं किए जा सकते हैं। –

+0

@DanielHilgarth: नहीं - कोड मेरे लिए संकलित है और * एक अतिरिक्त विधि नहीं बनाता है। इसे स्वयं आज़माएं :) –

0
using System; 
using System.Linq; 

namespace ConsoleApplication1 
{ 
    public static class Program 
    { 
     public static void Main() 
     { 
      Foo foo = new Foo(); 
      String[] names = new String[] { "Hello" }; 

      Console.WriteLine(String.Join(", ", names.Select(name => foo.GetName(name)))); 
     } 
    } 

    public class Foo { } 

    public static class Extensions 
    { 
     public static String GetName(this Foo foo, String name) 
     { 
      return name; 
     } 
    } 
} 
+0

यह काम करेगा, लेकिन यह सवाल नहीं है कि क्यों मूल कोड सी # 5 कंपाइलर के साथ संकलित करता है लेकिन सी # 4 कंपाइलर नहीं। –

+0

शायद सिस्टम में मामूली बदलाव हैं। 4.0 से 5.0 तक। मुझे इसे आगे की जांच करने दें। –

+2

मुझे संदेह है कि यह एक * कंपाइलर * परिवर्तन है, न कि .NET लाइब्रेरी परिवर्तन। –

1

संकलित किया जाएगा मुझे लगता है मैं यह करने के लिए 3 लक्ष्य ढांचे को बदलने के द्वारा तय हो गया वीएसएस 2010 में यह एक ही समस्या थी।5. फिर निर्माण करने की कोशिश कर रहा है। जैसा कि अपेक्षित है, आपका निर्माण असफल हो जाएगा लेकिन यह किक VSS 2010 में कुछ आंतरिक ध्वज शुरू या रीसेट करता है। अब, .NET 4.0 पर वापस स्विच करें और VSS ठीक से निर्माण शुरू कर देगा।

+0

एसओ, जूल में आपका स्वागत है। भविष्य में, कृपया सुनिश्चित करें कि आपके उत्तर यह सुझाव नहीं देते हैं कि उपयोगकर्ता ऐसा कुछ करने का प्रयास करें जो आपके लिए काम नहीं करता है जब आप उन्हें पहले से ही समाधान दे चुके हैं। – Brian

+0

@ ब्रायन लेकिन सब कुछ काम किया? 3.5 पर स्विच करें - संकलन करने का प्रयास करें - संकलन अपेक्षित के रूप में विफल रहता है - 4 पर वापस स्विच करें - वीएस एक किक हो जाता है और काम करना शुरू कर देता है। – GSerg

0

ऐसा लगता है कि यह ग # में एक बग 4 संकलक कि ग # 5 संकलक में तय किया गया था।

Console.WriteLine(string.Join(", ", names.Select(foo.GetName))); 

Console.WriteLine(string.Join(", ", names.Select(new Func<string, string>(foo.GetName)))); 

के लिए एक वाक्यात्मक चीनी भले ही foo.GetName एक विस्तार विधि है। उत्तरार्द्ध वीएस -2010 में काम करता है जो पूर्व नहीं करता है।

सी # भाषा विनिर्देश की धारा 6.6, जब एक विधि के लिए अंतर्निहित रूपांतरण के बारे में बात कैसे रूपांतरण होता है की प्रक्रिया का वर्णन और की तुलना में कहते हैं:

ध्यान दें कि यह प्रक्रिया एक प्रतिनिधि के निर्माण के लिए नेतृत्व कर सकते हैं एक विस्तार विधि के लिए, अगर §7.6.5.1 के एल्गोरिथ्म एक उदाहरण विधि को खोजने में विफल लेकिन एक विस्तार विधि मंगलाचरण के रूप में ई (ए) के आह्वान पर कार्रवाई करने में सफल होता है (§7.6.5.2)। इस प्रकार एक प्रतिनिधि ने को विस्तार विधि के साथ-साथ इसके पहले तर्क को कैप्चर किया।

इस आधार पर मैं पूरी तरह से इस लाइन VS2010 और VS2012 (के बाद से शब्दों कल्पना में परिवर्तन नहीं होता है) में दोनों काम करने की उम्मीद थी, लेकिन ऐसा नहीं है। तो मैं यह कह रहा हूँ कि यह एक बग है।

यहाँ आईएल जब वी.एस. 2012 में संकलित कैसा दिखता है (टिप्पणियां मेरे हैं):

// pushes comma 
L_0017: ldstr ", " 

// pushes names variable 
L_001c: ldloc.1 

// pushes foo variable 
L_001d: ldloc.0 

// pushes pointer to the extension method 
L_001e: ldftn string ConsoleApplication3.Extensions::GetName(class ConsoleApplication3.Foo, string) 

// pops the instance of foo and the extension method pointer and pushes delegate 
L_0024: newobj instance void [mscorlib]System.Func`2<string, string>::.ctor(object, native int) 

// pops the delegate and the names variable 
// calls Linq.Enumerable.Select extension method 
// pops the result (IEnumerable<string>) 
L_0029: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!1> [System.Core]System.Linq.Enumerable::Select<string, string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, !!1>) 

// pops comma, the IEnumerable<string> 
// pushes joined string 
L_002e: call string [mscorlib]System.String::Join(string, class [mscorlib]System.Collections.Generic.IEnumerable`1<string>) 

// pops joined string and displays it 
L_0033: call void [mscorlib]System.Console::WriteLine(string) 

// method finishes 
L_0038: ret 

आप देख सकते हैं, प्रतिनिधि वस्तु दृष्टान्त (foo) और विधि सूचक से बाहर बनाई गई है, और यह वही है जो वीएस -2010 में भी होना चाहिए। और यदि आप प्रतिनिधि निर्माण new Func<string, string>(foo.GetName) स्पष्ट रूप से निर्दिष्ट करते हैं।