2016-04-08 3 views
1

Я попытался еще более сузить проблему в Flush StreamWriter at the end of its lifetime реализации одноэлементно типа Самозапирающийся StreamWriter:Самозакрывающиеся StreamWriter одноточечно

class Foo : System.IO.StreamWriter 
{ 
    private static readonly Foo instance = new Foo("D:/tmp/test"); 

    private Foo(string path) 
     : base(path) 
    { 
    } 

    ~Foo() 
    { 
     this.Close(); 
    } 

    public static Foo Instance 
    { 
     get 
     { 
      return instance; 
     } 
    } 
} 

планируемый эффект является то, что в примере программы, как

class Program 
{ 
    private static void Main(string[] args) 
    { 
     Foo.Instance.Write("asdf\n"); 
    } 
} 

сборщик мусора вызывает закрытие экземпляра Foo.

Это не работает. По-видимому, StreamWriter уже исчез, когда работает деструктор Foo, и я получаю System.ObjectDisposedException.

Как я могу позвонить Close() в потоке соответствующим образом и предотвратить потерю данных?

+0

Я имею см референс-источник в компании Microsoft для FileStream. Когда вызывается деструктор, уже есть некоторый файл attemp для записи в файл, поэтому вам не нужно делать то, что вы сделали. Проблема в том, что GC уже может закрыть дескриптор файла до того, как произойдет последний сбой, поэтому он может не работать. Ссылка: http://referencesource.microsoft.com/#mscorlib/system/io/filestream.cs –

+0

@ThariqNugrohotomo Вы имеете в виду код в 'FileStream.Dispose'? Я бы сказал, что 'Dispose' не вызывается в моем примере. – mkluwe

ответ

2

Видимо, StreamWriter уже нет, когда деструктор Foo в

работает

Да. При завершении программы, предполагая, что ваш объект получает GC'ed вообще (нет гарантии, что это будет), среда выполнения не предоставляет никаких гарантий относительно порядка, в котором он выполняет финализаторы. Оба объекта недоступны и имеют право на финализацию одновременно, поэтому их финализаторы могут работать в любом порядке.

Финализаторы есть только в качестве блокиратора обратного хода для багги кода. И они не на 100% надежны для этой цели. Именно поэтому вам следует много работать, чтобы избежать ошибок кода.

Вам понадобится детерминированный способ утилизации объекта singleton при выходе из процесса. Вы можете поместить это под контроль основной логики вашей программы, которая контролирует время жизни процесса, и избавляет ли он от одиночного (например, с помощью общедоступного метода, который вы пишете для этой цели). Другой альтернативой является подписка на событие AppDomain.ProcessExit в вашем конструкторе singleton, и обработчик должен закрыть синглтон там.

См эти вопросы, связанные для получения дополнительной информации:
How can I ensure that I dispose of an object in my singleton before the application closes?
Disposable singleton in C#

+0

Для записи: Я добавил 'System.AppDomain.CurrentDomain.ProcessExit + = (sender, eventArgs) => this.Close();' в конструкторе и удалил деструктор, чтобы сделать этот кусок кода игрушки. – mkluwe

Смежные вопросы