Как запретить компилятору C # / CLR оптимизировать неиспользуемые переменные в ОТЛАДОЧНЫХ сборках?

#c# #debugging

#c# #отладка

Вопрос:

Во время отладки я пытался сохранить промежуточные результаты вычисления в переменную, чтобы при выполнении условия точки останова я мог проверить это значение. Однако компилятор C # (или CLR) оптимизировал эту переменную как неиспользуемую. Я решил проблему, сделав переменную общедоступным полем класса, однако я хотел бы знать, есть ли простое решение этой проблемы.

Флажок «Оптимизировать код» снят. Конфигурация сборки — Debug.

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

Комментарии:

1. У вас есть конкретный сценарий? Локальные файлы обычно сохраняются в отладочной сборке. Также: какой компилятор (именно) вы используете здесь?

2. Компилятором является C # 4 (VS 2010, target framework 4.0), однако я только что провел несколько тестов и могу подтвердить, что локальные файлы сохраняются в отладочных сборках, за исключением итераторов, которые были в моем случае.

3. «итераторы» были ключевой деталью, которую мы тогда упустили… действительно, они проходят массовую переписывание; Я подозреваю, что добавление чего-то подобного WriteLine — лучший способ сохранить их в процессе загрузки

4. Да, но невозможно предоставить все соответствующие детали с самого начала, потому что обычно не ясно, какие детали имеют значение. Ваши комментарии указали мне правильное направление.

5. Для информации, вы не представляете это; p i.stack.imgur.com/E73Uz.png

Ответ №1:

Ленивым вариантом было бы …. использовать значение, в идеале таким образом, чтобы оно не сохранялось в стеке. Например:

  var tmp = SomeMethod();
 // your other code
 Debug.WriteLine(tmp);
  

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

Однако! Я должен подчеркнуть, что локальные файлы практически всегда сохраняются в неоптимизированной / отладочной сборке, поэтому я нахожу сценарий из вопроса трудным для понимания.

Ответ №2:

Если вы используете Visual Studio, почему бы просто не добавить точку останова в строке, следующей за строкой, на которой выполняется вычисление, а затем вы можете просто навести курсор на вычисление, чтобы увидеть результат во всплывающем окне intellisense / tooltip? Я также думаю, что вы можете добавить вычисление на экран «просмотр» и просмотреть результат таким же образом.

Обычно так я просматриваю результаты того, что я отлаживаю. В качестве альтернативы, вы могли бы просто использовать созданную вами временную переменную каким-нибудь простым способом, чтобы избежать получения предупреждения.

Например:

 Console.Write(tempVariable);
  

Комментарии:

1. Одним из недостатков Console здесь является то, что он будет сохранен в сборках выпуска, если вы забудете его удалить.

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

3. @MarcGravell Я согласен, именно поэтому я предложил использовать точку останова в первую очередь. Я думаю, если он решит использовать решение фактического использования переменной temp, то ваш способ (с использованием Debug) — гораздо лучший вариант.

4. @srgstm я не совсем понимаю, почему вы не можете установить точку останова. Вы пробовали это делать? Может быть, если вы опубликуете раздел своего кода, я мог бы помочь немного больше….

5. @giygas73 он этого не воображает; сценарий (см. Комментарии) представляет собой блок итератора: i.stack.imgur.com/E73Uz.png

Ответ №3:

Удобная утилита:

 using static _globals;

static class _globals
{
    [MethodImpl(MethodImplOptions.NoInlining), DebuggerHidden]
    public static void Nop<T>(out T x) => x = default(T);
};

class Program
{
    static void Main()
    {
        int i;     // unreferenced variable

        /// ...

        Nop(out i);

        /// ...
    }
};
  

Комментарии:

1. Вы устанавливаете для переменной значение по умолчанию, поэтому ее следует вызывать, например SetDefault() , not Nop() .

Ответ №4:

Вам нужно снять флажок «Оптимизировать код» в параметрах проекта для отладочной сборки.

Комментарии:

1. Из вопроса: флажок «Оптимизировать код» снят. Конфигурация сборки — Debug.

2. Это было добавлено немного после моего ответа.

3. Вы можете видеть, что я не редактировал вопрос. Замечание было с самого начала.

4. @srgstm на самом деле, мы этого не видим — существует 5-минутный льготный период, когда изменения не отслеживаются

Ответ №5:

В моем случае опция «Оптимизировать код» была снята, но я все равно столкнулся с этой проблемой. Я проверил это, построил проект, затем снял с него флажок и снова создал проект. Это исправило проблему для меня.

Комментарии:

1. Я проверил, сохранил решение, снял флажок и снова сохранил.