2012-11-23 51 views
1

我对C#比较陌生,所以如果这个问题的答案很明显,我很抱歉。数组的咖喱功能不能正常工作

我正在写一个程序的一部分,它存储了一个结构数组,而struct的一个元素是一个curried函数。

以下是代码造成的问题(只要我能最小化)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace CurryingProblem 
{ 
    class Program 
    { 
     public struct Value 
     { 
      public Func<decimal> Output; 
     } 
     public static decimal AddOne(decimal value) 
     { 
      return value + 1; 
     } 

     static void Main(string[] args) 
     { 
      Dictionary<string, Decimal> ThingsToAdd = new Dictionary<string, decimal>(); 
      Dictionary<string, Value> ThingsToPrint = new Dictionary<string, Value>(); 

      ThingsToAdd.Add("One", 1.0m); 
      ThingsToAdd.Add("Two", 2.0m); 
      foreach (KeyValuePair<string, Decimal> thing in ThingsToAdd) 
      { 
       Value value = new Value(); 
       value.Output =() => AddOne(thing.Value); 
       ThingsToPrint.Add(thing.Key, value); 
      } 
      Console.WriteLine(ThingsToPrint["One"].Output()); 
      Console.WriteLine(ThingsToPrint["Two"].Output()); 

      Console.ReadKey(); 
     } 
    } 
} 

这个方案的预期输出

2.0 
3.0 

但实际产量

部分
3.0 
3.0 

任何方向,我哪里出了错将是美好的。

+2

真的吗?因为我的复制和粘贴产生'2.0'和'3.0' ... –

+0

是的,我的肯定会产生错误的值。我正在运行Visual Studio 2008,.NET 3.5 SP1,如果这最终取决于版本 – JamesL

回答

3

你的问题类似于access to modified closure。这article by Eric Lippert解释得很好。您需要传递局部作用域的变量而不是传递循环thing.Value。创建一个新变量并分配thing.Value,以便传递本地副本。

static void Main(string[] args) 
    { 
     Dictionary<string, Decimal> ThingsToAdd = new Dictionary<string, decimal>(); 
     Dictionary<string, Value> ThingsToPrint = new Dictionary<string, Value>(); 

     ThingsToAdd.Add("One", 1.0m); 
     ThingsToAdd.Add("Two", 2.0m); 
     foreach (KeyValuePair<string, Decimal> thing in ThingsToAdd) 
     { 
      Value value = new Value(); 
      Decimal d = thing.Value; 
      value.Output =() => AddOne(d); 
      ThingsToPrint.Add(thing.Key, value); 
     } 
     Console.WriteLine(ThingsToPrint["One"].Output()); 
     Console.WriteLine(ThingsToPrint["Two"].Output()); 

     Console.ReadKey(); 
    } 
+0

这绝对有效,谢谢。我认为这归结为我不理解范围的微妙之处。 – JamesL

+0

我发现这篇文章对于理解http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx – Adil

+0

+1说明。 –