簡體   English   中英

為什么這個代碼不能在VS2010中用.NET 4.0編譯?

[英]Why doesn't this code compile in VS2010 with .NET 4.0?

不知怎的,下面的代碼不能在VS2010中編譯,而是在VS2012中編譯而不做任何更改。 VS2010中有問題的一行是

names.Select(foo.GetName)

錯誤CS1928:'string []'不包含'Select'的定義和最佳擴展方法重載'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;
        }
    }
}

更新的答案

我已經檢查過代碼片段names.Select(foo.GetName)在VS 2012中編譯,並且不在VS2010上編譯。

我不知道原因(確切地說是C#5.0或.NET 4.5或新API中的新功能)使其成為可能。

但是跟隨錯誤

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))))

但正如Jon Skeet在評論中指出的那樣,上面將通過創建一個新方法來添加另一個函數調用。

原文答案

為什么這個代碼不能用VS 4.0在VS 4.0中編譯?

您沒有將參數傳遞給名稱。 您正在傳遞方法名稱,而不是Func<T1,T2>


以下將編譯

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

我在VSS 2010中遇到了同樣的問題。我通過將目標框架更改為3.5來解決此問題。 然后試圖建立。 正如預期的那樣,您的構建將失敗但是此踢法啟動或重置VSS 2010中的一些內部標志。現在,切換回.NET 4.0並且VSS將開始正確構建。

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;
        }
    }
}

看起來它是c#4編譯器中修復的c#4編譯器中的錯誤。

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

是一種語法糖

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

即使foo.GetName是一個擴展方法。 后者在VS2010中工作,前者沒有。

在討論方法的隱式轉換時,C#語言規范的第6.6節描述了轉換發生的過程,而不是說:

請注意,如果§7.6.5.1的算法無法找到實例方法但成功處理E(A)的調用作為擴展方法調用,則此過程可以導致創建擴展方法的委托(第7.6節) .5.2)。 這樣創建的委托捕獲擴展方法及其第一個參數。

基於此,我完全希望這條線在VS2010和VS2012中都能正常工作(因為規范中的措辭不會改變),但事實並非如此。 所以我推斷這是一個錯誤。

這是IL在VS 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)和方法指針創建的,這正是VS2010中應該發生的事情。 如果您明確指定委托創建new Func<string, string>(foo.GetName)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM