Модуль оценивается только один раз, его экспортируемые переменные по существу образуют единичный объект. Они используются всеми модулями, которые их импортируют.
В вашем первом примере есть одно обещание, которое используется (ну, не совсем, ссылается на ) дважды.
Во втором примере есть одна функция, которая вызывается дважды.
На основе того, что Отражатель показывает, последние два (a4
и dummyAgeMatch
) кэшируются компилятором C#3.0 MS (в полях, названных "CS$ <> 9 _CachedAnonymousMethodDelegate5" и "CS$ <> 9 _CachedAnonymousMethodDelegate6" в моей конкретной сборке).
Эти могут кэшироваться, тогда как, очевидно, другие зависят от полученных переменных.
Я не полагаю, что поведение получает мандат спецификацией, но Моно компилятор ведет себя почти таким же способом (с различными именами переменной).
Ну, для ответа на конкретный вопрос: последние два являются единственными, которые кэшируются, так как они ничего не получают. Вы видите это в отражателе (но это не симпатично). Конечно, можно настроить их для создания их допускающими повторное использование путем передачи в args:
Action<Program> a1 = p => Console.WriteLine(p.field);
Action<int> a2 = i => Console.WriteLine(i);
Action<Program> a3 = p => Console.WriteLine(p.ToString());
Action a4 = () => Console.WriteLine(default(int));
Func<Dummy, Dummy, bool> dummyAgeMatch = (l, r) => l.age == r.age;
И передача this
в a1
/a3
, и local
в a2
. Поскольку ни один из них непосредственно ничего больше не получает, они могут все кэшироваться (CS$<>9__CachedAnonymousMethodDelegate5
через CS$<>9__CachedAnonymousMethodDelegate9
для меня, по крайней мере). Конечно, они затем теряют способность повторно присвоиться (ранее полученный) переменная непосредственно, но защитникам FP не понравится это так или иначе;-p можно всегда пасовать назад обновленное значение как возвращаемое значение или объявлять тип делегата с ref
аргументы (я не рекомендую это, хотя).