Расширяя наблюдения Фабио , следующая короткая и полная программа испытаний раскрывает JIT-чувствительные детали поведения TypeAttributes.BeforeFieldInit
, сравнивая .NET 3.5 с последняя версия (по состоянию на конец 2017 года) .NET 4.7.1 , а также демонстрирует потенциальные опасности для вариаций типа сборки в каждой версии. [1]
using System;
using System.Diagnostics;
class MyClass
{
public static Object _field = Program.init();
public static void TouchMe() { }
};
class Program
{
static String methodcall, fieldinit;
public static Object init() { return fieldinit = "fieldinit"; }
static void Main(String[] args)
{
if (args.Length != 0)
{
methodcall = "TouchMe";
MyClass.TouchMe();
}
Console.WriteLine("{0,18} {1,7} {2}", clrver(), methodcall, fieldinit);
}
};
Ниже представлен вывод консоли при запуске этой программы во всех комбинациях {x86, x64} и {Debug, Release} . Я вручную добавил дельта-символ Δ
(не излучаемый программой), чтобы подчеркнуть различия между двумя версиями .NET.
.NET 2.0 / 3.5
2.0.50727.8825 x86 Debug
2.0.50727.8825 x86 Debug TouchMe fieldinit
2.0.50727.8825 x86 Release fieldinit
2.0.50727.8825 x86 Release TouchMe fieldinit
2.0.50727.8825 x64 Debug
2.0.50727.8825 x64 Debug TouchMe fieldinit
2.0.50727.8825 x64 Release
2.0.50727.8825 x64 Release TouchMe fieldinit
.NET 4.7.1
4.7.2556.0 x86 Debug
4.7.2556.0 x86 Debug TouchMe fieldinit
4.7.2556.0 x86 Release Δ
4.7.2556.0 x86 Release TouchMe Δ
4.7.2556.0 x64 Debug
4.7.2556.0 x64 Debug TouchMe fieldinit
4.7.2556.0 x64 Release
4.7.2556.0 x64 Release TouchMe Δ
Как отмечалось во вступлении, возможно, более интересно, чем версия 2.0 / 3.5 против 4.7 дельты - это различия в пределах текущая версия .NET, так как они показывают, что, хотя поведение инициализации поля в настоящее время является более согласованным между x86
и x64
, чем это было раньше, все же можно испытать существенное различие в поведении инициализации поля времени выполнения между вашими Debug
и Release
сборками сегодня.
Семантика будет зависеть от того, вызовете ли вы случайный или кажущийся несвязанным статический метод для класса или нет, поэтому, если это приведет к ошибке для вашего общего дизайна, это может быть довольно таинственным и трудным для отслеживания .
Примечания
1. Вышеуказанная программа использует следующую служебную функцию для отображения текущей CLR версии:
static String clrver()
{
var s = typeof(Uri).Assembly.Location;
return FileVersionInfo.GetVersionInfo(s).ProductVersion.PadRight(14) +
(IntPtr.Size == 4 ? " x86 " : " x64 ") +
#if DEBUG
"Debug ";
#else
"Release";
#endif
}