Сохранение класса на диск при утилизации: есть ли в моем коде ошибки? - PullRequest
2 голосов
/ 30 сентября 2010

Я пытаюсь создать простой класс, который сериализует себя на диск, когда он больше не используется. Код у меня сейчас (см. Ниже). Код, который у меня сейчас есть, кажется, работает, но я не совсем уверен в своих знаниях, поэтому мне интересно, видит ли кто-нибудь еще какие-либо существенные проблемы с этим кодом.

void IDisposable.Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

~MyClass()
{
    Dispose(false);
}

protected virtual void Dispose(bool disposing)
{
    if (!this.disposed)
    {
        MemoryStream ms = new MemoryStream();
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(ms, this);
        byte[] output = Dostuff(ms);
        File.WriteAllBytes(DBPATH, output);
    }
    this.disposed = true;
}

Ответы [ 3 ]

6 голосов
/ 30 сентября 2010

Это, вероятно, сработает, но я бы этого не сделал.Делая это, вы потенциально выполняете потенциально опасный код в потоке финализации.Если что-то пойдет не так, вы будете в плохой форме ...

Утилизация действительно ничего не должна делать, кроме как распоряжаться своими ресурсами.Я настоятельно рекомендую перенести это в другой метод и сделать его частью API объекта вместо того, чтобы полагаться на IDisposable для обработки обработки за вас.

5 голосов
/ 30 сентября 2010

Практически невозможно правильно написать финализатор, и выполнение такого рода работы за один раз - всего лишь рецепт катастрофы. Не говоря уже о том, что это снизит производительность и станет невозможным для отладки. Правило 1 для финализаторов - никогда не используйте их. Правило 2 (только для опытных пользователей) - не используйте их, если вы действительно не уверены в этом.

Если это просто для веселого хобби-проекта, то здесь нет никакого реального вреда, и он, вероятно, будет работать достаточно хорошо, но я бы заплакал, если бы я увидел что-то подобное в рабочей базе кода.

Если вы действительно хотите сделать что-то подобное, то я бы сделал это явным вызовом и просто использовал бы финализатор для обнаружения случаев во время отладки, когда явный метод не был вызван, например,

class MyClass
{
    private bool dirty; // set this whenever the object changes

    ~MyClass 
    {
        if (this.dirty) 
        {
            Debug.Fail("Object was not saved.");
        }
    }

    public void Save()
    {
        if (this.dirty)
        {
            // TODO: do the save
            this.dirty = false;
        }
    }
}
4 голосов
/ 30 сентября 2010

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

Во-вторых, вам следует избегать сложной логики внутри ваших финализаторов.Например, было бы намного лучше сохранить ваш сериализуемый класс в постоянное хранилище в метод Storage.Dispose.А из метода финализатора только записывайте предупреждение в файл журнала, потому что он показывает неподходящий класс Использование хранилища:

[Serializable]
public class MySerializableClass {
}

public sealed class MyStorage : IDisposable {

  ~MyStorage()
  {
     Dispose(false);
  }


  public void Dispose()
  {
     Dispose(true);
     GC.SuppressFinalize(this);
  }


  void Dispose(bool disposing)
  {
     if (!this.disposed)
     {
        if (disposing)
        {
          //We can access to all managed resources
          using (var ms = new MemoryStream())
          {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, mySerializableClass);
            byte[] output = Dostuff(ms);
            File.WriteAllBytes(DBPATH, output);
          }
        }
        else
        {
           //Inappropriate storage usage!
           //We can't guarantee that mySerializableClass object would
           //properly saved to persistant storage.
           //Write warning to log-file. We should fix our code
           //and add appropriate usage!
        }
    }
    this.disposed = true;
 }

}
...