Ссылка на numbers
передается значением .Тем не менее, запрос обрабатывается лениво, а базовый массив является изменяемым.
Так что это значит?
var arr = new[]{1,2,3,};
var q = arr.Select(i=>i*2);
Console.WriteLine(string.Join(", ",q.ToArray())); //prints 2, 4, 6
arr[0]=-1;
Console.WriteLine(string.Join(", ",q.ToArray())); //prints -2, 4, 6
// q refers to the original array, but that array has changed.
arr = new[]{2,3,4};
Console.WriteLine(string.Join(", ",q.ToArray())); //prints -2, 4, 6
//since q still refers to the original array, not the variable arr!
Как правило, это может сбить с толку довольно быстро, если вы измените переменные, а неих базовые объекты, поэтому лучше избегать таких изменений.
Например:
var arr = new[]{1,2,};
var arr2 = new[]{1,2,};
var q = from a in arr
from b in arr2
select a*b;
// q is 1,2,2,4
arr = new[]{0,1}; //irrelevant, arr's reference was passed by value
// q is still 1,2,2,4
arr2 = new[]{0,1}; //unfortunately, relevant
// q is now 0, 1, 0, 2
Чтобы понять это, вам нужно понять детали процесса компиляции.Выражения запроса определяются как эквивалент синтаксиса метода расширения (arr.Select...
), который интенсивно использует замыкания.В результате фактически только первая перечислимая или запрашиваемая ссылка имеет свою ссылку, переданную по значению, остальные захватываются в замыканиях, и это означает, что их ссылки эффективно передаются по ссылке.Смущены еще? Избегайте изменения таких переменных, чтобы ваш код можно было обслуживать и читать.