C # - вопрос, связанный с дизайном (взять два) - PullRequest
1 голос
/ 06 января 2010

Я задал вопрос ранее сегодня, но думаю, что мне нужно подойти к нему по-другому (к тому же произошло «зависание» в отношении DataSet).

Вот класс, который инкапсулирует создание шрифта (другими словами, он читает данные из файла xml и создает шрифт во время выполнения на основе того, что он читает из этого файла):

public class FontCreator
{
    private Font m_TheFont = null;

    public FontCreator( ... some parameters ... )
    {
        m_TheFont = GetTheFont();
    }

    public Font TheFont
    {
        return m_TheFont;
    }

    private Font GetTheFont()
    {
        // code, and more code, that eventually leads to:

        Font f = new Font(fntFamily, fntSize, fntStyle);
        return f;
    }
}

Потребитель класса FontCreator выглядит примерно так:

public class TheConsumer()
{
    private FontCreator m_FontCreator = null;

    public TheConsumer()
    {
        m_FontCreator = new m_FontCreator( ... some parameters ... );
        Initialize();
    }

    private void Initialize()
    {
        InitializeThis();
        InitializeThat();
    }

    private void InitializeThis()
    {
        .... some code ...
        SomeObject.ApplyFont(m_FontCreator.TheFont);
    }

    private void InitializeThat()
    {
        ... some code ...
        SomeObject.ApplyFont(m_FontCreator.TheFont);
    }
}

Какой код вы добавляете и где, чтобы явно вызывать метод Dispose для TheFont?

Ответы [ 4 ]

3 голосов
/ 06 января 2010

Если вы не хотите поддерживать ссылку на TheFont после его первоначального использования, тогда вызовите его метод Dispose в вашем конструкторе, сразу после Initialize. Если вы хотите какое-то время поддерживать TheConsumer и поддерживать ссылку на TheFont, это становится более интересным. Два варианта:

  1. Вы можете использовать метод утилизации TheFont из Destructor объекта TheConsumer. Это не распространенная практика и имеет проблемы. В основном, это не вызывается, пока не произойдет сборка мусора. Лучше это:
  2. Вы можете заставить сам объект TheConsumer реализовывать IDisposable и вызывать TheFont.Dispose из TheConsumer.Dispose. Поскольку TheConsumer реализует IDisposable, код, который использует it , должен вызвать его метод Dispose.

Редактировать в ответ на грубый комментарий! Да, я должен был дать понять, что нужно использовать только 1 в дополнение к 2, если вообще. Я знаю, что все разработчики повсюду должны замечать, когда реализован IDisposable, но они часто этого не делают. Если указанный управляемый ресурс может действительно оставаться в течение длительного времени и вызывать проблемы, если он не будет правильно удален, у меня иногда возникает безопасный метод Dispose () в деструкторе объекта, содержащего ссылку. Это так неправильно? :)

3 голосов
/ 06 января 2010

Я в замешательстве, если вы хотите быстро использовать объект создателя шрифтов, тогда реализуйте IDisposable на FontCreater и используйте

using(m_FontCreator = new FontCreater(....))
{
   InitializeThis();
   InitializeThat();
}

Если вам нужно сохранить экземпляр FontCreater в течение времени жизни TheConsumer, то реализуйте IDisposable в классах FontCreater и TheConsumer.

public class TheConsumer : IDisposable
{
  void Dispose()
  {
     if(m_FontCreator != null)
          m_FontCreator.Dispose();
  }
}

затем используйте TheConsumer класс, такой как

using(TheConsumer consumer = new TheConsumer(....))
{
  ....
}
3 голосов
/ 06 января 2010
public TheConsumer()
{
    using (m_FontCreator = new m_FontCreator( ... some parameters ... ))
    {
        Initialize();
    }
}
1 голос
/ 06 января 2010

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

Ответ 2: Если вам нужны встроенные поля, как показано в коде, то и класс FontCreator, и класс Consumer должны реализовать IDisposable. Но не деструктор (Финализатор).
Основным аргументом для этого является то, что FontCreator является «владельцем» шрифта и поэтому должен нести ответственность. И Потребитель отвечает за Творца таким же образом.

Как уже отмечали другие, похоже, что вы, по крайней мере, можете избежать поля m_FontCreator в классе Consumer. Но это зависит от остальной части кода, m_FontCreator используется в другом месте?

...