Почему целочисленная переменная, созданная из проекции, не может быть увеличена? - PullRequest
0 голосов
/ 16 января 2019

Я столкнулся с нишей в C #, которую я не ожидал. К счастью, мой юнит-тест обнаружил неожиданное поведение, но я удивлен и не понимаю, почему он так себя ведет. Я воспроизвел проблему со следующим кодом.

static void Main(string[] args)
{
    var initialCollection = new bool[] { false, true };
    var projectedCollection = initialCollection.Select(o => (initialObj: o, Counter: 0)).ToArray();

    for (int i = 0; i < 10; i++)
    {
        var objectFromProjection = projectedCollection.First(o => o.initialObj == (i % 2 == 0));
        Console.WriteLine($"For initial obj {objectFromProjection.initialObj}, counter is now {++objectFromProjection.Counter}");
    }

    Console.ReadKey();
}

Так как я добавил ToArray после проекции, я ожидал, что переменная счетчика не будет повторно инициализироваться каждый раз до нуля. Тем не менее, он повторно инициализируется до 0 для каждой итерации цикла for.

Вот вывод:

For initial obj True, counter is now 1
For initial obj False, counter is now 1
For initial obj True, counter is now 1
For initial obj False, counter is now 1
For initial obj True, counter is now 1
For initial obj False, counter is now 1
For initial obj True, counter is now 1
For initial obj False, counter is now 1
For initial obj True, counter is now 1
For initial obj False, counter is now 1

Вот то, что я думал, что это сделает:

For initial obj True, counter is now 1
For initial obj False, counter is now 1
For initial obj True, counter is now 2
For initial obj False, counter is now 2
For initial obj True, counter is now 3
For initial obj False, counter is now 3
For initial obj True, counter is now 4
For initial obj False, counter is now 4
For initial obj True, counter is now 5
For initial obj False, counter is now 5

Почему счетчик сбрасывается в ноль вместо сохранения увеличенного значения?

Ответы [ 2 ]

0 голосов
/ 16 января 2019
 var objectFromProjection = projectedCollection.First(o => o.initialObj == (i % 2 == 0));
 Console.WriteLine($"For initial obj {objectFromProjection.initialObj}, 
                     counter is now {++objectFromProjection.Counter}");

Имеет смысл каждый раз, когда цикл запускается objectFromProjection ValueTuple создается, и его значение всегда будет равно 1, так как objectFromProjection всегда будет иметь 1 элемент, поскольку .First() всегда возвращает единственный элемент ..

Полагаю, это кое-что прояснит для вас.

 var initialCollection = new bool[] { false, true };
  var projectedCollection = initialCollection.Select(o => (initialObj: o, Counter: 0)).ToArray();
  (bool initialObj, int Counter) d = new ValueTuple<bool,int>();
  for (int i = 0; i < 10; i++)
   {
     d = projectedCollection.First(o => o.initialObj == (i % 2 == 0));
     Console.WriteLine($"For initial obj {d.initialObj}, counter is now {++d.Counter}");
     }
0 голосов
/ 16 января 2019

Потому что вы имеете дело с значением Tuple. Обратите внимание:

for (int i = 0; i < 10; i++)
{
    var objectFromProjection = projectedCollection.First(o => o.initialObj == (i % 2 == 0));

    //Always false
    Console.WriteLine(ReferenceEquals(projectedCollection[0], objectFromProjection));
    Console.WriteLine(ReferenceEquals(projectedCollection[1], objectFromProjection));
}
...