2015-03-23 2 views
-1

У меня есть простой класс FeatureToggle, который использует FilesSystemWatcher для просмотра файла app.config. Если произошел сбой в файле .config, он перезагрузит настройки из раздела appSettings. Я сделал его реализовать IDisposable, однако я не могу использовать с помощью оператора {}, потому что я хочу, чтобы файлы .config просматривались во время работы программы, однако я хочу, чтобы Dispose() вызывался при завершении процесса, t добавить finally() в основную программу. Как я могу вызвать Dispose(). Могу ли я использовать финализатор здесь?Реализация IDisposable для класса FileSystemWatcher

FeatureToggle:

public sealed class FeatureToggle : IDisposable 
     { 
      private static readonly FeatureToggle instance = new FeatureToggle(); 

      private static FeatureWatcher featureWatcher = new FeatureWatcher(); 

      private static ConcurrentDictionary<string, bool> features = new ConcurrentDictionary<string, bool>(); 

      private bool disposed; 

      static FeatureToggle() 
      { 
      } 

      private FeatureToggle() 
      { 
      } 

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

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

      public bool Enabled(string featureName) 
      { 
       string path = this.GetAssemblyPath(); 
       if (featureWatcher.GetWatcher(path) == null) 
       { 
        FileSystemWatcher watcher = featureWatcher.AddWatcher(path); 
        if (watcher != null) 
        { 
         watcher.Changed += this.OnChanged; 
         this.Refresh(path); 
        } 
       } 

       return this.Get(featureName); 
      } 

      private void Add(string key, bool value) 
      { 
       features.AddOrUpdate(key, value, (k, v) => value); 
      } 

      private void Dispose(bool disposing) 
      { 
       if (this.disposed) 
       { 
        return; 
       } 

       if (disposing) 
       { 
        featureWatcher.Dispose(); 
        featureWatcher = null; 
        features = null; 
       } 
      } 

      private bool Get(string key) 
      { 
       bool value; 
       if (features.TryGetValue(key, out value)) 
       { 
        return value; 
       } 

       return false; 
      } 

      private string GetAssemblyPath() 
      { 
       return AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; 
      } 

      private IEnumerable<KeyValuePair<string, bool>> LoadConfig(string path) 
      { 
       ExeConfigurationFileMap configMap = new ExeConfigurationFileMap { ExeConfigFilename = path }; 
       Configuration config = ConfigurationManager.OpenMappedExeConfiguration(
        configMap, 
        ConfigurationUserLevel.None); 

       var settings = 
        config.AppSettings.Settings.Cast<KeyValueConfigurationElement>() 
         .Where(x => x.Key.StartsWith("FeatureToggle.")) 
         .ToDictionary(o => o.Key.ToString(CultureInfo.InvariantCulture), o => Convert.ToBoolean(o.Value)); 

       return settings; 
      } 

      private void OnChanged(object source, FileSystemEventArgs e) 
      { 
       // app.config changed - run update 
       this.Refresh(e.FullPath); 
      } 

      private void Refresh(string path) 
      { 
       foreach (var kv in this.LoadConfig(path)) 
       { 
        this.Add(kv.Key, kv.Value); 
       } 
      } 
     } 

FileWatcher:

public class FeatureWatcher : IDisposable 
    { 
     private static ConcurrentDictionary<string, FileSystemWatcher> watchers; 

     private bool disposed; 

     public FeatureWatcher() 
     { 
      watchers = new ConcurrentDictionary<string, FileSystemWatcher>(); 
     } 

     public FileSystemWatcher AddWatcher(string path) 
     { 
      if (this.GetWatcher(path) == null) 
      { 
       var parentPath = Path.GetDirectoryName(path); 
       var watcher = new FileSystemWatcher 
            { 
             Path = parentPath, 
             NotifyFilter = NotifyFilters.LastWrite, 
             Filter = "*.config" 
            }; 

       watchers.TryAdd(path, watcher); 
       watcher.EnableRaisingEvents = true; 
       return watcher; 
      } 

      return null; 
     } 

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

     public FileSystemWatcher GetWatcher(string path) 
     { 
      FileSystemWatcher watcher; 
      if (!watchers.TryGetValue(path, out watcher)) 
      { 
       return null; 
      } 

      return watcher; 
     } 

     protected virtual void Dispose(bool disposing) 
     { 
      if (this.disposed) 
      { 
       return; 
      } 

      if (disposing) 
      { 
       // Clean up managed resources 
       if (watchers != null) 
       { 
        foreach (var watcher in watchers.Values) 
        { 
         watcher.EnableRaisingEvents = false; 
         watcher.Dispose(); 
        } 

        watchers = null; 
       } 

       this.disposed = true; 
      } 
     } 
    } 
+2

Почему вы хотите избавиться от него, когда процесс завершается? Ресурсы будут автоматически освобождаться и нет чистого преимущества. –

+0

Но FileSystemWatcher реализует IDisposable, поэтому мне нужно реализовать IDisposable в классе, который его использует. Это неправильно? – ShaneKm

+0

Это хорошая идея, но поскольку вы не освобождаете ее до выхода процесса, нет смысла вызывать dispose –

ответ

0

Если у вас есть приложение WPF, приложение WinForms или службы, все они имеют события Initialized, который является хорошее место для инициализации вашего класса и Closed, что является хорошим местом для его размещения. (В консольном приложении вы можете просто поместить все в попытке .. окончательно)