1

私はC#に比較的慣れていないので、この質問に対する答えが明らかな場合は、お詫び申し上げます。

私が書いているプログラムには、構造体の配列を格納する部分があり、構造体の要素の1つはカリー化された関数です。

以下は、問題を引き起こしているコードの部分です(私ができる限り最小限に抑えられています)

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

私がどこを間違えたかについてのどんな方向も素晴らしいでしょう。

4

1 に答える 1

3

あなたの質問は、変更された閉鎖へのアクセスに似ています。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();
    }
于 2012-11-23T05:25:58.523 に答える