Почему события ведут себя иначе в этом случае? - PullRequest
0 голосов
/ 24 ноября 2010

Следующая программа

static IEnumerable<Action> Create()
{
    foreach (var i in Enumerable.Range(0, 2))
    {
        yield return () => { Console.Write(i); };
    }
}

static void Main(string[] args)
{
    foreach (var func in Create())
    {
        func();
    }

    Console.ReadLine();
}

Выходы

01

И эта программа

static event Action SomethingHappened;

static void Register()
{
    foreach (var i in Enumerable.Range(0, 2))
    {
        SomethingHappened += () => { Console.Write(i); };
    }
}

static void Main(string[] args)
{
    Register();
    SomethingHappened();
    Console.ReadLine();
}

вывод

11

Почему это так?Как заставить программу 2 выводить 01?

Ответы [ 2 ]

3 голосов
/ 24 ноября 2010

Вы захватываете переменную цикла в своем лямбда-выражении. Это означает, что когда делегат будет окончательно вызван, он будет использовать последнее значение переменной ... которое всегда будет равно 1. Попробуйте это:

foreach (var i in Enumerable.Range(0, 2))
{
    int copy = i;
    SomethingHappened += () => { Console.Write(copy); };
}

... затем прочитайте сообщение Эрика Липперта в блоге об этом.

1 голос
/ 24 ноября 2010

Во второй программе переменная i фиксируется лямбда-выражением. Чтобы получить правильное поведение, сделайте локальную копию, прежде чем использовать ее в лямбде. Например.

foreach (var i in Enumerable.Range(0, 2))
{
    var local = i;
    SomethingHappened += () => { Console.Write(local); };
}
...