У меня есть простой класс 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;
}
}
}
Почему вы хотите избавиться от него, когда процесс завершается? Ресурсы будут автоматически освобождаться и нет чистого преимущества. –
Но FileSystemWatcher реализует IDisposable, поэтому мне нужно реализовать IDisposable в классе, который его использует. Это неправильно? – ShaneKm
Это хорошая идея, но поскольку вы не освобождаете ее до выхода процесса, нет смысла вызывать dispose –