Хорошо, чтобы ответить на конкретный вопрос: последние два являются единственными, которые кэшируются, так как они ничего не фиксируют. Вы можете увидеть это в отражателе (но это не красиво). Конечно, вы можете настроить их на сделать их многократно используемыми, передав аргументы:
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
аргументами (хотя я не рекомендую это).