Какие (если есть) локально определенные делегаты кэшируются между вызовами методов? - PullRequest
6 голосов
/ 15 января 2009

Это было упомянуто в моем другом вопросе, и я подумал, что было бы полезно добавить его в запись. В следующей программе, которые, если таковые имеются, локально определенных делегатов кэшируются между вызовами метода Work, а не создаются каждый раз с нуля?

namespace Example
{
    class Dummy
    {
        public int age;
    }

    class Program
    {
        private int field = 10;

        static void Main(string[] args)
        {
            var p = new Program();

            while (true)
            {
                p.Work();
            }
        }

        void Work()
        {
            int local = 20;

            Action a1 = () => Console.WriteLine(field);
            Action a2 = () => Console.WriteLine(local);
            Action a3 = () => Console.WriteLine(this.ToString());
            Action a4 = () => Console.WriteLine(default(int));
            Func<Dummy, Dummy, bool> dummyAgeMatch = (l, r) => l.age == r.age;

            a1.Invoke();
            a2.Invoke();
            a3.Invoke();
            a4.Invoke();
            dummyAgeMatch.Invoke(new Dummy() { age = 1 }, new Dummy(){ age = 2 });
        }
    }
}

Ответы [ 2 ]

7 голосов
/ 15 января 2009

На основании того, что показывает Reflector, последние два (a4 и dummyAgeMatch) кэшируются компилятором MS C # 3.0 (в полях с именами «CS $ <> 9_CachedAnonymousMethodDelegate5» и «CS $ <> 9_CachedAnonymousMethodDelegate6» в моя конкретная сборка).

Эти могут быть кэшированы, тогда как другие, очевидно, зависят от захваченных переменных.

Я не верю, что поведение предписано спецификацией, но компилятор Mono ведет себя примерно так же (с разными именами переменных).

5 голосов
/ 15 января 2009

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

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 аргументами (хотя я не рекомендую это).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...