Подтвердить что ты не робот

Почему моя функция Close не вызывается?

 class Program : CriticalFinalizerObject
    {
        static void Main(string[] args)
        {

            Program p = new Program();
            TextWriterTraceListener listener = new TextWriterTraceListener(@"C:\trace.txt");
            Trace.Listeners.Clear(); // Remove default trace listener
            Trace.Listeners.Add(listener);
            Trace.WriteLine("First Trace"); // Generate some trace messages
            Trace.WriteLine("Perhaps last Trace.");

        }

        ~Program()
        {
            Trace.Close();
        }
    }

Я получаю размер файла = 0

финишер должен выполнить, потому что я получаю от CriticalFinalizerObject

Я не хочу использовать Trace.Close() не в Finalizer.

изменить

после @eric Ответ Lippert: Ive повторно отредактировал код, пытаясь его сопоставить с: область ограниченного выполнения (но все еще нет)

  [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    class Program : CriticalFinalizerObject
    {

        static void Main(string[] args)
        {
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
            }
            catch (Exception e)
            {
            }
            finally
            {
                Program p = new Program();
                TextWriterTraceListener listener = new TextWriterTraceListener(@"C:\trace1.txt");
                Trace.Listeners.Clear();
                Trace.Listeners.Add(listener);
                Trace.WriteLine("First Trace");
                Trace.WriteLine("Perhaps last Trace.");
            }
        }

        ~Program()
        {
            Trace.Flush();
        }
    }
4b9b3361

Ответ 1

В документации четко указано:

В классах, полученных из класса CriticalFinalizerObject, общая среда исполнения CLR гарантирует, что всем критическим кодам завершения будет предоставлена ​​возможность выполнить, если финализатор будет следовать правилам CER, даже в ситуациях, когда CLR принудительно выгружает домен приложения или прервать поток. Если финализатор нарушает правила для CER, он может не успешно выполнить

Выполняет ли ваш финализатор все правила для ограниченной области выполнения?

ОБНОВЛЕНИЕ:

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

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

Делает ли ваш финализатор любую из этих пяти вещей? Если это так, то не требуется, чтобы CLR чествовал ваше желание, чтобы финализатор всегда запускался.

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

Что останавливает дрожание от сбора мусора p до начала трассировки? Ничего! Джиттер знает, что p никогда не будет использоваться снова, и он полностью в пределах своих прав собирать его сразу после его выделения. Флеш может происходить в любой момент в потоке финализатора, в том числе до того, как произойдет запись трассировки или посередине любого из них.

Ответ 2

Потому что вы не создали экземпляр класса Program.

Вы можете прочитать здесь:

Этот метод автоматически вызывается после того, как объект становится недоступным, если объект не был освобожден от завершения вызовом SuppressFinalize. Во время выключения домена приложения Finalize автоматически вызывается для объектов, которые не освобождаются от завершения, даже те, которые все еще доступны. Финализация автоматически вызывается только один раз на данном экземпляре, если объект не будет повторно зарегистрирован с использованием механизма, такого как ReRegisterForFinalize и GC.SuppressFinalize не был вызван впоследствии.

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

ОБНОВЛЕНИЕ: рассмотрите возможность использования Trace.AutoFlush = true;, если вы хотите, чтобы сообщение было записано.

UPDATE: (Почему функция Close не вызывается?) На самом деле вы вызываете функцию Close (если ничего не происходит в других финализаторах). Если вы оставите по умолчанию TraceListener (удалить Trace.Listeners.Clear() вызов), вы увидите, что все строки успешно записаны в окно вывода.

Проблема здесь в том, что StreamWriter (созданный внутри TextWriterTraceListener) не имеет финализатора. Поэтому он не очищает все данные до файла. Что вам нужно сделать:

FileStream file = new FileStream(@"C:\trace.txt", FileMode.OpenOrCreate);
StreamWriter writer = new StreamWriter(file);
GC.SuppressFinalize(file);
GC.SuppressFinalize(file.SafeFileHandle);
var listener = new TextWriterTraceListener(writer);

На самом деле вам нужно закрыть файл вручную на финализаторе.

Ответ 3

В С# вы не можете быть уверены в том, когда или когда вы вызываете ваш финализатор, потому что GC обрабатывает это. Поэтому, если у вас есть ресурсы для выпуска, лучше всего создать класс, который реализует IDisposable и использовать его следующим образом:

using (MyResourceHolder rh = new MyResourceHolder()) {
    // ...
} // rh.Dispose() is called implicitly

В методе Dispose вы можете вызвать Trace.Close().

См. http://msdn.microsoft.com/en-us/library/system.idisposable.aspx для хорошей реализации IDisposable.