C# 包含参数的Lambda表达式。在VS2008中出现意外结果,在VS2013中效果良好

C# 包含参数的Lambda表达式。在VS2008中出现意外结果,在VS2013中效果良好,c#,lambda,C#,Lambda,我不知道如何用语言准确地解释这个问题。我已经编写了代码来重现这个问题,并且我已经尽力使代码易于阅读 delegate string del(); static void Main(string[] args) { string[] ss = { "a", "b" }; Dictionary<string, del> dic = new Dictionary<string, delSS>(); foreach (string s in ss) {

我不知道如何用语言准确地解释这个问题。我已经编写了代码来重现这个问题,并且我已经尽力使代码易于阅读

delegate string del();
static void Main(string[] args)
{

    string[] ss = { "a", "b" };
    Dictionary<string, del> dic = new Dictionary<string, delSS>();
    foreach (string s in ss) {
        dic[s] = () => s;
    }
    foreach (string s in ss) {
        System.Console.WriteLine("{0}:{1}", s, dic[s]());
    }
    System.Console.ReadLine();
}
这是VS2013的结果。 但在VS2008中,结果是

a:b
b:b
我在VS2013中尝试了从3.0到4.5的.Net Framework版本,以及所有版本 它们中的大多数给出了相同的结果。 我还在VS2008中尝试了3.0和3.5,它们也给出了相同的结果。我认为这意味着这不是框架的缺陷,而是编译器的缺陷。 我正在为WinCE 6.0开发一个应用程序,它只在VS2008和更早版本中受支持。这就是为什么我必须使用VS2008。我在调试WinCE应用程序时发现了这个问题。我认为这是Compact框架的一个缺陷,但事实证明这是VS2008的一个缺陷。
有人知道如何修复它吗?

好吧,编译器变得更好了,我这样说;)

试一试


这将为每个
s
创建一个新的变量/值,以便闭包不会指向将由
foreach
循环突变到最后的
s

在闭包中捕获循环变量是一件棘手的事情。VS2013为您整理了它,这很好,但我认为它根本不安全

Jon Skeet在这里(以及在他的书中)很好地解释了这一点:。代码质量工具(如Resharper)在您尝试执行此操作时会发出警告

这里有一个解决方案。 我做了以下修改,并在vs2008中试用过,效果非常好 委托字符串del(字符串sr)

static void Main()
{
字符串[]ss={“a”,“b”};
Dictionary dic=新字典();
foreach(ss中的字符串s)
{
dic[s]=(sr)=>sr;
}
foreach(ss中的字符串s)
{
System.Console.WriteLine(“{0}:{1}”,s,dic[s].Invoke(s));
}
System.Console.ReadLine();
}
  • del委托现在具有参数sr
  • 您需要在使用点调用委托,并传入变量's'
  • 使用委托的事实意味着您应该利用可以将参数传递给委托的优势。 当您将变量放入lambda函数中时,它会使CLR选择foreach循环指针的最后一个位置作为s变量

    添加委托字符串del(字符串sr);在主()之前
    a:b
    b:b
    
       foreach (string s in ss) {
            var closed = s;
            dic[s] = () => closed;
        }
    
        static void Main( )
        {
    
            string[] ss = { "a", "b" };
            Dictionary<string, del> dic = new Dictionary<string, del >();
            foreach (string s in ss)
            {
                dic[s] = (sr) => sr;
            }
            foreach (string s in ss)
            {
                System.Console.WriteLine("{0}:{1}", s, dic[s].Invoke(s));
            }
            System.Console.ReadLine();
        }