Служба Windows с FileSystemWatcher и Timer - убедитесь, что все утилизируется - PullRequest
2 голосов
/ 12 октября 2011

Я создал приложение службы Windows C #, которое запускает FileSystemWatcher для наблюдения за каталогом для создания файла. Когда файл найден, я создаю экземпляр пользовательского класса, который анализирует файл (CSV) и вызывает веб-сервис с его содержимым. Служба является несколько асинхронной и возвращает уникальный номер, который необходимо использовать для последующих вызовов, чтобы проверить его ход. В моем классе процесса я создаю таймер, чтобы постоянно проверять, завершено ли задание. Когда я закончу, я dispose использую и close включаю свой таймер, но я просто хочу убедиться, что мой класс будет собирать мусор, и у меня не будет никаких утечек памяти.

Код выглядит следующим образом (сокращенно для краткости):

Мой основной класс обслуживания:

    protected override void OnStart(string[] args)
    {
        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Path = "path";
        watcher.Filter = "file";
        watcher.Created += new FileSystemEventHandler(watcher_Created);
        watcher.EnableRaisingEvents = true;
    }

    static void watcher_Created(object sender, FileSystemEventArgs e)
    {
        FileProcessor p = new FileProcessor();
        p.Process(e.FullPath);

        //Will this instance of p stick around until the timer within it is finished?
    }

FileProcessor.cs

    class FileProcessor
    {
        private System.Timers.Timer timer = new System.Timers.Timer();
        private string id;

        public FileProcessor()
        {
            timer.Elapsed += new ElapsedEventHandler(OnTimer);
            timer.Enabled = false;
            timer.AutoReset = true;
        }

        public void Process(string filename)
        {
            //Read file <snipped>

            //Call web service and get id
            id = CallWebService();

            //Create a timer for 10 seconds and start it
            timer.Interval = 10000;
            timer.Enabled = true;
        }


        private bool IsFinished(string id)
        {
            //Call web service to see if job is finished, true if finished
            //<snipped>
        }


        private void ProcessResults()
        {
            //Job is finished, process results

            //Call cleanup method to dispose of timer
            Cleanup();
        }

        private void OnTimer(object source, ElapsedEventArgs e)
        {
            if (!IsFinished(id))
            {
                //Keep timer running, check result again next timer event
                return;
            }
            else
            {
                //Stop timer
                timer.Stop();

                //Process Results
                ProcessResults(response);
            }
        }


        private void Cleanup()
        {
            timer.Close();
            timer.Dispose();
        }
    }

Мой вопрос заключается в том, должен ли мой экземпляр "p" держаться (не быть GC'ed), пока мой таймер не будет уничтожен? Будет ли он когда-нибудь разрушен? Должен ли мой класс FileProcessor реализовать IDisposable, чтобы я мог обернуть его в блок использования? Меня не беспокоит, что это однопоточный, потому что я ожидаю, что он будет обрабатывать только один файл в день, и процесс не должен занять более 10 минут, чтобы вернуться к просмотру следующего файла, который будет создан.

1 Ответ

5 голосов
/ 12 октября 2011

Вы на правильном пути. FileSystemWatcher реализует класс Component , который требует утилизации после использования. Поскольку дело обстоит именно так, правильным подходом было бы иметь класс FileProcessor , реализующий IDisposable, как вы предложили.

Поскольку объект FileProcessor будет работать в течение длительного периода времени, вы не сможете использовать , используя оператор . Это потому, что объект будет пытаться избавиться до того, как это будет сделано его работой.

В этом случае я бы реализовал событие в FileProcessor , чтобы уведомить потребителя о завершении обработки. Когда это будет завершено, я вызову метод Dispose для объекта FileProcessor . Метод Dispose должен выполнить всю очистку, необходимую для этого объекта - IE: таймер, наблюдатель и т. Д.

Для справки, это хорошая статья , в которой изложены некоторые рекомендации относительно того, когда и как использовать интерфейс IDisposable. Кроме того, в качестве хорошей практики вам нужно будет обернуть вызовы потребителя в блоки try / catch - вы должны убедиться, что, что бы ни случилось, вы попытаетесь освободить ресурсы.

...