c# - Why is this output variable in my LINQ expression NOT problematic? -
given next code:
var strings = enumerable.range(0, 100).select(i => i.tostring()); int outvalue = 0; var someenumerable = strings.where(s => int.tryparse(s, out outvalue)) .select(s => outvalue); outvalue = 3; //enumerating on someenumerable here shows ints 0 99
i able see "snapshot" of out parameter each iteration. why work correctly instead of me seeing 100 3's (deferred execution) or 100 99's (access modified closure)?
first define query, strings
knows how generate sequence of strings, when queried. each time value asked generate new number , convert string.
then declare variable, outvalue
, , assign 0
it.
then define new query, someenumerable
, knows how to, when asked value, next value query strings
, seek parse value and, if value can parsed, yields value of outvalue
. 1 time again, have defined query can this, have not done any of this.
you set outvalue
3
.
then inquire someenumerable
it's first value, asking implementation of select
value. compute value inquire where
its first value. where
inquire strings
. (we'll skip few steps now.) where
0
. phone call predicate on 0
, calling int.tryparse
. side effect of outvalue
set 0
. tryparse
returns true
, item yielded. select
maps value (the string 0
) new value using selector. selector ignores value , yields value of outvalue
@ point in time, 0
. our foreach
loop whatever 0
.
now inquire someenumerable
sec value, on next iteration of loop. asks select
value, select
asks where,
where asks strings
, strings
yields "1"
, where
calls predicate, setting outvalue
1
side effect, select
yields current value of outvalue
, 1
. foreach
loop whatever 1
.
so key point here due way in where
, select
defer execution, performing work when values needed, side effect of where
predicate ends beingness called before each projection in select
. if didn't defer execution, , instead performed of tryparse
calls before of projections in select
, then see 100
each value. can simulate enough. can materialize results of where
collection, , see results of select
100
repeated on , over:
var someenumerable = strings.where(s => int.tryparse(s, out outvalue)) .tolist()//eagerly evaluate query point .select(s => outvalue);
having said of that, query have not particularly design. whenever possible should avoid queries have side effects (such where
). fact query both causes side effects, , observes side effects creates, makes next of rather hard. preferable design rely on purely functional methods aren't causing side effects. in context simplest way create method tries parse string , returns int?
:
public static int? tryparse(string rawvalue) { int output; if (int.tryparse(rawvalue, out output)) homecoming output; else homecoming null; }
this allows write:
var someenumerable = s in strings allow n = tryparse(s) n != null select n.value;
here there no observable side effects in query, nor query observing external side effects. makes whole query far easier reason about.
c# .net vb.net linq
No comments:
Post a Comment