Wednesday, 15 January 2014

c# - Why is this output variable in my LINQ expression NOT problematic? -



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