c# - Are delegates created via lambda expressions guaranteed to be cached? -
it seems working way, stated somewhere in spec or implementation detail can't depend on? i'm trying speed property/field name extraction faster creating expression tree once , caching it. wrapping tree in lambda , using key cache. , break down miserably if runtime decides create new delegate every time hits same lambda expression.
// keyvaluepair<string, t> getpair<t>(func<expression<func<t>>> val)... var item = new item { num = 42 }; var pair = getpair(() => () => item.num); // guaranteed same instance? // pair.key = "num" // pair.value = 42
edit: ok, here full thing. seems works , doesn't seem generate garbage in process.
another edit: ok, changed it, doesn't seem capture anything, , works faster!
using system; using system.diagnostics; using system.linq.expressions; using system.runtime.compilerservices; class program { static void main(string[] args) { var pair = new pair<int>(); var pair2 = new pair<string>(); var item = new item { num = 42, word = "answer" }; double ratio = 1; var sw = stopwatch.startnew(); (int = 0;; i++) { if ((i & 0xfff) == 0 && sw.elapsedmilliseconds > 2000) { console.writeline("literal: {0:n0}", i); ratio *= i; break; } assign(pair, "num", item.num); assign(pair2, "word", item.word); assign(pair, "num", item.num); assign(pair2, "word", item.word); assign(pair, "num", item.num); assign(pair2, "word", item.word); assign(pair, "num", item.num); assign(pair2, "word", item.word); } sw = stopwatch.startnew(); (int = 0; ; i++) { if ((i & 0xfff) == 0 && sw.elapsedmilliseconds > 2000) { item = new item { num = 42, word = "answer" }; console.writeline("expression: {0:n0}", i); ratio /= i; break; } assign4(pair, item, () => => it.num); assign4(pair2, item, () => => it.word); assign4(pair, item, () => => it.num); assign4(pair2, item, () => => it.word); assign4(pair, item, () => => it.num); assign4(pair2, item, () => => it.word); assign4(pair, item, () => => it.num); assign4(pair2, item, () => => it.word); } console.writeline(ratio.tostring("f3")); console.readline(); } static void assign<t>(pair<t> pair, string name, t value) { pair.name = name; pair.value = value; } static void assign4<t, u>(pair<t> pair, u item, func<expression<func<u, t>>> value, [callerfilepath]string path = "", [callerlinenumber]int line = 0) { int key = ((path.length << 20) + line) % cache<u, t>.length; // int key = value.gethashcode() % cache<t>.length; while (true) { var bucket = cache<u, t>.records[key]; if (bucket.literal == null) break; if (object.referenceequals(bucket.literal, value)) { pair.name = bucket.fieldname; pair.value = bucket.getter(item); return; } key += 1; if (key == cache<u, t>.length) key = 0; } var tree = value(); var getter = tree.compile(); string name = (tree.body memberexpression).member.name; cache<u, t>.records[key] = new cache<u, t>.record { literal = value, fieldname = name, getter = getter, }; pair.name = name; pair.value = getter(item); } } class cache<u, t> { public struct record { public func<expression<func<u, t>>> literal; public string fieldname; public func<u, t> getter; } public const int length = 997; public static record[] records = new record[length]; } class pair<t> { public string name; public t value; } class item { public int num; public string word; }
it can't same instance in case - captured variable (item
) different each time execute pair of lines.
even can same instance, isn't guaranteed. remember of ms c# compiler, lambda expressions don't capture any variables (not this
) cached in static variables - i'm not sure else is.
Comments
Post a Comment