Мы переносим приложение в .NET 4.0 (с версии 3.5). Одна из проблем, с которыми мы сталкиваемся, воспроизводится только в очень специфических условиях:
- Только в сборке Release
- Только с включенной оптимизацией и/или информацией об отладке, установленной только для pdb.
Под этим я подразумеваю, что если я отключу оптимизацию и задаю полную информацию об отладке, проблема исчезнет.
Этот код отлично работает на .NET 3.5, в режиме Release с оптимизацией и т.д. включен и длится долгое время.
Я действительно не хочу предлагать, чтобы в компиляторе С# была ошибка, так что действительно мой вопрос: есть ли какие-либо методы, которые я могу использовать для отслеживания того, что мы можем делать неправильно, чтобы вызвать неправильную оптимизацию?
Я пытаюсь сузить эту проблему до небольшого тестового примера, чтобы опубликовать здесь код.
Edit:
Я обнаружил проблему следующим образом:
У нас есть этот код в конструкторе формы:
public ConnectionForm()
{
LocalControlUtil.Configure("ConnectionForm", "Username", usernameLabel);
LocalControlUtil.Configure("ConnectionForm", "Password", passwordLabel);
LocalControlUtil.Configure("ConnectionForm", "Domain", domainLabel);
LocalControlUtil.Configure("ConnectionForm", "Cancel", cancelButton);
LocalControlUtil.Configure("ConnectionForm", "OK", okButton);
}
Эти вызовы относятся к некоторому пользовательскому коду локализации. Конструктор для этой формы вызывается из другой сборки. Метод LocalControlUtil.Configure
вызывает Assembly.GetCallingAssembly()
, который возвращает правильное значение для всех вышеуказанных вызовов, кроме последнего.
Я могу изменить порядок строк выше, добавить новые или удалить текущие, и каждый раз, когда это последняя строка, которая не работает.
Я предполагаю, что это JIT, вставляющий последний вызов метода в место, где был вызван конструктор (в другой сборке). Добавление [MethodImpl(MethodImplOptions.NoInlining)]
в конструктор выше устраняет проблему.
Кто-нибудь знает, почему это происходит? Мне кажется странным, что последняя строка может быть только встроена. Это новое поведение в .NET 4.0?
Изменить 2:
Я сузил это сейчас до устранения хвостового вызова, я предполагаю, что вызванный новый хвост в .NET 4.
В приведенном выше коде последний вызов LocalControlUtil.Configure
в конструкторе исключается и помещается в вызывающий метод, который находится в другой сборке. Поскольку метод вызывает Assembly.GetCallingAssembly
, мы не получаем правильную сборку назад.
Есть ли способ остановить компилятор (или JIT или что-то в этом роде) от устранения хвостового вызова?