Компилятор C # и кэширование локальных переменных - PullRequest
3 голосов
/ 15 января 2009

РЕДАКТИРОВАТЬ: Упс - как правильно сказано, не было бы никакого способа узнать, чувствителен ли конструктор для рассматриваемого класса к тому, когда или сколько раз он вызывается, или же объект состояние изменяется во время метода, поэтому каждый раз его нужно создавать с нуля. Не обращайте внимания на словарь и просто рассмотрите делегатов, созданных в ходе выполнения метода: -)


Допустим, у меня есть следующий метод с локальной переменной "Словарь типа".

void TakeAction(Type type)
{
    // Random types chosen for example.
    var actions = new Dictionary<Type, Action>()
    {
        {typeof(StringBuilder), () =>
            {
                // ..
            }},
         {typeof(DateTime), () =>
            {
                // ..
            }}
    };

    actions[type].Invoke();
}

Словарь всегда будет одинаковым при вызове метода. Может ли компилятор C # заметить это, только создать его один раз и кэшировать где-нибудь для использования в будущих вызовах метода? Или он просто будет создаваться с нуля каждый раз? Я знаю, что это может быть поле вмещающего класса, но мне кажется, что такая вещь должна содержаться в методе, который его использует.

Ответы [ 4 ]

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

Краткий ответ: нет.

Немного более длинный ответ: я верю, что он кеширует результат создания делегата из лямбда-выражения, которое ничего не захватывает (включая «это»), но это довольно особый случай.

Правильный способ изменить ваш код: объявить личную статическую переменную только для чтения для словаря.

private static readonly Dictionary<Type,Action> Actions = 
    new Dictionary<Type, Action>()
{
    { typeof(StringBuilder), () => ... },
    { typeof(DateTime), () => ... },
}

void TakeAction(Type type)
{
    Actions[type].Invoke();
}
7 голосов
/ 15 января 2009

Как компилятор C # должен знать, что это "тот же" словарь каждый раз? Вы явно создаете новый словарь каждый раз. C # не поддерживает статические локальные переменные, поэтому вы должны использовать поле. В этом нет ничего плохого, даже если никакой другой метод не использует это поле.

Было бы плохо, если бы компилятор C # делал подобные вещи. Что если конструктор переменной использует случайный ввод? :)

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

Чтобы любой компилятор мог это сделать, у него должен быть какой-то способ иметь гарантии для следующих проблем:

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

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

Теперь, то, что в C # и .NET нет механизмов для предоставления этих гарантий, вероятно, не является причиной того, почему поддержка такого рода оптимизации не осуществляется компилятором, но они должны быть реализованы в первую очередь. Также могут быть и другие гарантии, которые должны быть у компилятора, прежде чем он сможет это сделать, о которых я не знаю.

Изменение, предложенное Джоном Скитом, в основном означает, что Я знаю, что эти две гарантии верны для моего кода , и, таким образом, вы сами контролируете ситуацию.

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

Этот словарь будет создаваться заново каждый раз; в противном случае, например, вы можете поместить другие слова в словарь, и намерение будет потеряно.

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