I have written the following code:
List<int> ints = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
int start = 0;
int end = 5;
int limit = 10;
IEnumerable<int> GetRange(List<int> list, int startGR, int endGR)
{
for (int i = startGR; i < endGR; i++)
{
yield return list[i];
}
}
IEnumerable<int> query = GetRange(ints, start, end).Where(x => x < limit);
void FirstMethod(IEnumerable<int> query1, ref int start1, ref int end1, ref int limit1)
{
start1 = 4;
end1 = 9;
limit1 = 8;
SecondMethod(query1);
start1 = 9;
end1 = 14;
limit1 = 16;
SecondMethod(query1);
}
void SecondMethod(IEnumerable<int> query2)
{
Console.WriteLine(string.Join(", ", query2));
}
FirstMethod(query, ref start, ref end, ref limit);
The console prints:
1, 2, 3, 4, 5
1, 2, 3, 4, 5
Instead of expected:
5, 6, 7
10, 11, 12, 13, 14
Please explain why doesn't deferred execution work here with updated values.
Is there a way to make this work as I expect?
GetRange(List<int> list, int startGR, int endGR)
will receive copy of passedstart
andend
upon the invocation (i.e. "by value"), hence here:after that
ref
manipulations done withstart
andend
inFirstMethod
will have no effect, so you will have aIEnumerable<int>
which will process range from0
to5
i.e. the initial values of the variables.You can try using LINQ with it's deferred execution and the fact that lambda will capture the local variables via closures (as you do with
Where(x => x < limit)
):Though personally I'm not a big fun of such approach.