РЕДАКТИРОВАТЬ: Хорошо, я делаю некоторые успехи в этом.Возможны три бинарных коммутатора (как минимум):
- оптимизирован ли код;т. е. флаг
/o+
или /o-
в командной строке.Кажется, это не имеет значения. - Независимо от того, выполняется ли код в отладчике или нет.Кажется, это не имеет значения.
- Уровень создаваемой отладочной информации, то есть флаг командной строки
/debug+
, /debug-
или /debug:full
или /debug:pdbonly
.Только /debug+
или /debug:full
приводит к сбою.
Дополнительно:
- Если вы отделите код
Main
от кода TestDestructor
, вы можетескажу, что именно режим компиляции кода Main
имеет значение - Насколько я могу судить, IL, сгенерированный для
/debug:pdbonly
, такой же, как для /debug:full
в методесамо по себе , так что это может быть явной проблемой ...
РЕДАКТИРОВАТЬ: Хорошо, теперь это действительно странно.Если я разбираю «сломанную» версию, а затем снова собираю ее, она работает:
ildasm /out:broken.il Program.exe
ilasm broken.il
ilasm имеет три различных параметра отладки: /DEBUG
, /DEBUG=OPT
и /DEBUG=IMPL
.При использовании любого из первых двух происходит сбой - при использовании последнего он работает.Последний описан как включающий оптимизацию JIT, так что, по-видимому, в этом и есть разница ... хотя, на мой взгляд, должен по-прежнему иметь возможность собирать объект в любом случае.
Возможно, это связано с моделью памяти в терминах DestructorCalled
.Он не является энергозависимым, поэтому нет гарантии, что запись из потока финализатора «видна» вашим тестовым потоком.
Финализаторы, конечно, вызываются в этом сценарии.После создания переменной volatile этот автономный эквивалентный пример (который мне проще запустить) наверняка выведет True для меня.Конечно, это не доказательство: без volatile
код не гарантированно потерпит неудачу;это просто не гарантировано работать.Можете ли вы заставить свой тест провалиться после того, как сделает его переменной переменной?
using System;
class TestDestructor
{
public static volatile bool DestructorCalled;
~TestDestructor()
{
DestructorCalled = true;
}
}
class Test
{
static void Main()
{
TestDestructor testDestructor = new TestDestructor();
var array = new object[] { testDestructor };
array = null;
testDestructor = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(TestDestructor.DestructorCalled);
}
}
РЕДАКТИРОВАТЬ: Я только что видел этот сбой при сборке с Visual Studio, но это было хорошо скомандная строка.Сейчас заглядываю в ИЛ ...