class Settings {
string _directory;
public Observer CreateObserver() {
return new Observer(_directory);
}
pubic void Save(string path) {
// ...
}
public static Settings Load(string path) {
// ...
}
}
Логика сохранения настроек в XML, где есть делегат
Есть один объект, который смотрит, какие файлы появились в определённом каталоге.
При инициализации объекта, его делегату присваивается(?) функция, находящаяся вне этого объекта, которая будет обрабатывать список новых файлов в каталоге.
Ну и имя каталога тоже передаётся при инициализации.
Приложение завершается и объекту нужно запомнить, куда смотреть нужно, чтобы смотреть туда же после начала работы приложения и, чтобы заново не производить его инициализацию. Имя каталога схоронить легко, а что делать с делегатом?
Какие могут быть идеи?
По-моему, всё-таки лучше перенести сохранение и восстановления списка каталогов во "внешний" объект, а потом заново инициализировать наблюдателя- это сделает работу приложения более понятной и простой в изменении.
Но этим сохранением вроде бы как должен заниматься сам наблюдающий объект по логике, его же всё-таки настройки.
Код:
Конкретней уже некуда. Есть форма и есть объект, который отслеживает изменения в каталогах. Через форму задаётся, какие каталоги отслеживать. Объект, который этим занимается, создаёт в себе словарь, где хранятся структуры всех наблюдаемых каталогов, вернее, структуры, которые хранят метаданные - имя каталога, его FileSystemWatcher и делегаты на методы формы, которые буду что-то делать с именем нового файла в каталоге.
Может быть, неправильно, что форма будет обрабатывать данные о новых или удалённых файлах и нужно ввести ещё какой-нибудь объект-ядро для этого, а форму оставить взаимодействовать только с БД, где сразу будет готовая информация о файлах.
Код:
class Database {
readonly ICollection<DirectoryEntry> _entries = new List<DirectoryEntry>();
public ICollection<DirectoryEntry> Entries {
get { return _entries; }
}
public Observer CreateObserver(object obj) {
var observer = new Observer();
foreach (var entry in _entries) {
entry.Register(observer, obj);
}
return observer;
}
}
class DirectoryEntry {
public string Path { get; set; }
public string MethodName { get; set; }
public void Register(Observer observer, object instance) {
var method = new Method(instance, MethodName);
observer.Add(Path, method);
}
public void Unregister(Observer observer) {
observer.Remove(Path);
}
}
class Observer : Disposable {
readonly ICollection<ObservableDirectory> _directories = new List<ObservableDirectory>();
public void Add(string path, Method method) {
_directories.Add(new ObservableDirectory(path, method));
}
public void Remove(string path) {
var item = _directories.SingleOrDefault(directory => directory.IsMatch(path));
if (item != null) {
_directories.Remove(item);
}
}
protected override void Dispose(bool disposing) {
if (disposing) {
foreach (var item in _directories) {
item.Dispose();
}
}
}
}
sealed class ObservableDirectory : Disposable {
readonly string _path;
readonly FileSystemWatcher _watcher;
readonly Method _method;
public ObservableDirectory(string path, Method method) {
_path = path;
_watcher = new FileSystemWatcher(path);
_method = method;
_watcher.Created += OnFileCreated;
}
public bool IsMatch(string path) {
return path.ToUpper() == _path.ToUpper();
}
string GetNewName(string name) {
return _method.Invoke<string>(name);
}
void OnFileCreated(object sender, FileSystemEventArgs e) {
var name = GetNewName(e.Name);
File.Move(e.FullPath, name);
}
protected override void Dispose(bool disposing) {
if (disposing) {
_watcher.Dispose();
}
}
}
class Method {
readonly object _instance;
readonly MethodInfo _method_info;
public Method(object instance, string name) {
_instance = instance;
const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
_method_info = instance.GetType().GetMethod(name, flags);
}
public T Invoke<T>(params object[] args) {
try {
return (T)_method_info.Invoke(_instance, args);
}
catch (TargetInvocationException ex) {
throw ex.InnerException;
}
}
}
abstract class Disposable : IDisposable {
bool _disposed;
protected abstract void Dispose(bool disposing);
public void Dispose() {
if (_disposed) {
return;
}
_disposed = true;
Dispose(true);
GC.SuppressFinalize(this);
}
public ~Disposable() {
if (!_disposed) {
Dispose(false);
}
}
}
readonly ICollection<DirectoryEntry> _entries = new List<DirectoryEntry>();
public ICollection<DirectoryEntry> Entries {
get { return _entries; }
}
public Observer CreateObserver(object obj) {
var observer = new Observer();
foreach (var entry in _entries) {
entry.Register(observer, obj);
}
return observer;
}
}
class DirectoryEntry {
public string Path { get; set; }
public string MethodName { get; set; }
public void Register(Observer observer, object instance) {
var method = new Method(instance, MethodName);
observer.Add(Path, method);
}
public void Unregister(Observer observer) {
observer.Remove(Path);
}
}
class Observer : Disposable {
readonly ICollection<ObservableDirectory> _directories = new List<ObservableDirectory>();
public void Add(string path, Method method) {
_directories.Add(new ObservableDirectory(path, method));
}
public void Remove(string path) {
var item = _directories.SingleOrDefault(directory => directory.IsMatch(path));
if (item != null) {
_directories.Remove(item);
}
}
protected override void Dispose(bool disposing) {
if (disposing) {
foreach (var item in _directories) {
item.Dispose();
}
}
}
}
sealed class ObservableDirectory : Disposable {
readonly string _path;
readonly FileSystemWatcher _watcher;
readonly Method _method;
public ObservableDirectory(string path, Method method) {
_path = path;
_watcher = new FileSystemWatcher(path);
_method = method;
_watcher.Created += OnFileCreated;
}
public bool IsMatch(string path) {
return path.ToUpper() == _path.ToUpper();
}
string GetNewName(string name) {
return _method.Invoke<string>(name);
}
void OnFileCreated(object sender, FileSystemEventArgs e) {
var name = GetNewName(e.Name);
File.Move(e.FullPath, name);
}
protected override void Dispose(bool disposing) {
if (disposing) {
_watcher.Dispose();
}
}
}
class Method {
readonly object _instance;
readonly MethodInfo _method_info;
public Method(object instance, string name) {
_instance = instance;
const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
_method_info = instance.GetType().GetMethod(name, flags);
}
public T Invoke<T>(params object[] args) {
try {
return (T)_method_info.Invoke(_instance, args);
}
catch (TargetInvocationException ex) {
throw ex.InnerException;
}
}
}
abstract class Disposable : IDisposable {
bool _disposed;
protected abstract void Dispose(bool disposing);
public void Dispose() {
if (_disposed) {
return;
}
_disposed = true;
Dispose(true);
GC.SuppressFinalize(this);
}
public ~Disposable() {
if (!_disposed) {
Dispose(false);
}
}
}