如何创建一个观察来自 FileSystemWatcher 的 `Renamed` 和 `Changed` 事件的 `Observable`
How to create a `Observable` which observes both `Renamed` and `Changed` events from `FileSystemWatcher`
我想创建一个Reactive
Observable
,可以同时观察Renamed
和Changed
我正在使用 FileSystemWatcher
监控文件夹中的修改和重命名文件。我只想在事件稳定下来后处理它(因为有时 Changed
事件可能会引发多次)。
所以我选择.net的Reactive Extension
.
的Throttle
函数
我可以通过观察单个 Changed
事件来设法完成这项工作,但无法弄清楚如何在单个 [=15= 中观察 Changed
和 Renamed
].
这是我为单个 Changed
事件所做的:
var watcher = new FileSystemWatcher();
watcher.Path = "d:\test";
var observable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
ev => watcher.Changed += ev,
ev => watcher.Changed -= ev
);
var d = observable.Throttle(TimeSpan.FromSeconds(5))
.Subscribe(
a => Console.WriteLine($"Watcher type:{a.EventArgs.ChangeType }, file:{a.EventArgs.Name }, sender: {a.Sender}"),
ex => Console.WriteLine("observer error:" + ex.ToString()),
() => Console.WriteLine("observer complete.")
);
但是当我想同时观看这两个事件时,VS 告诉我 FileSystemEventHandler
和 RenamedEventHandler
不兼容(尽管 RenamedEventArgs
可以安全地转换为 FileSystemEventArgs
):
var observable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
ev => {
watcher.Changed += ev;
//Error
watcher.Renamed += ev;
},
ev => {
watcher.Changed -= ev;
//Error
watcher.Renamed -= ev;
});
我知道我可以将 ev
转换为兼容的委托,但我想知道如何记录该委托并将其从事件中删除?因为我读到匿名委托不能从 event
中删除,除非在注册时记录它(如(此问题)[Adding and Removing Anonymous Event Handler 中所述)。 Aslo,这样做同样一点也不优雅...
Func<FileSystemEventHandler, RenamedEventHandler> renameDelegate = (FileSystemEventHandler h) =>
{
return (object sender, RenamedEventArgs args) => h(sender, args);
};
var observable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
ev => { watcher.Changed += ev;
//registered delegate
watcher.Renamed += renameDelegate(ev);
},
ev => { watcher.Changed -= ev;
//this seems not to be identical with the one registered
watcher.Renamed -= renameDelegate(ev); });
);
那么我如何在同一个 Observable
中同时观察 Changed
和 Renamed
事件?
编辑 1
感谢@Enigmativity 的回答,我的最终代码如下(示例代码):
var o1 = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
ev => watcher.Changed += ev,
ev => watcher.Changed -= ev);
var o2 = Observable.FromEventPattern<RenamedEventHandler, RenamedEventArgs>(
ev => watcher.Renamed += ev,
ev => watcher.Renamed -= ev)
.Select(x => new System.Reactive.EventPattern<FileSystemEventArgs>(x.Sender, x.EventArgs));
var o = Observable.Merge(o1, o2);
var d = o.Throttle(TimeSpan.FromSeconds(5))
.Subscribe(
a => Console.WriteLine($"Watcher type:{a.EventArgs.ChangeType }, file:{a.EventArgs.Name }, sender: {a.Sender}"),
ex => Console.WriteLine("observer error:" + ex.ToString()),
() => Console.WriteLine("observer complete.")
操作方法如下:
var observable =
Observable
.Using(
() => new FileSystemWatcher() { Path = "d:\test" },
watcher =>
Observable
.Merge(
Observable
.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
ev => watcher.Changed += ev,
ev => watcher.Changed -= ev)
.Select(x => new
{
x.EventArgs.Name,
x.EventArgs.FullPath,
x.EventArgs.ChangeType,
OldName = (string)null,
OldFullPath = (string)null,
}),
Observable
.FromEventPattern<RenamedEventHandler, RenamedEventArgs>(
ev => watcher.Renamed += ev,
ev => watcher.Renamed -= ev)
.Select(x => new
{
x.EventArgs.Name,
x.EventArgs.FullPath,
x.EventArgs.ChangeType,
x.EventArgs.OldName,
x.EventArgs.OldFullPath
})));
我想创建一个Reactive
Observable
,可以同时观察Renamed
和Changed
我正在使用 FileSystemWatcher
监控文件夹中的修改和重命名文件。我只想在事件稳定下来后处理它(因为有时 Changed
事件可能会引发多次)。
所以我选择.net的Reactive Extension
.
Throttle
函数
我可以通过观察单个 Changed
事件来设法完成这项工作,但无法弄清楚如何在单个 [=15= 中观察 Changed
和 Renamed
].
这是我为单个 Changed
事件所做的:
var watcher = new FileSystemWatcher();
watcher.Path = "d:\test";
var observable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
ev => watcher.Changed += ev,
ev => watcher.Changed -= ev
);
var d = observable.Throttle(TimeSpan.FromSeconds(5))
.Subscribe(
a => Console.WriteLine($"Watcher type:{a.EventArgs.ChangeType }, file:{a.EventArgs.Name }, sender: {a.Sender}"),
ex => Console.WriteLine("observer error:" + ex.ToString()),
() => Console.WriteLine("observer complete.")
);
但是当我想同时观看这两个事件时,VS 告诉我 FileSystemEventHandler
和 RenamedEventHandler
不兼容(尽管 RenamedEventArgs
可以安全地转换为 FileSystemEventArgs
):
var observable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
ev => {
watcher.Changed += ev;
//Error
watcher.Renamed += ev;
},
ev => {
watcher.Changed -= ev;
//Error
watcher.Renamed -= ev;
});
我知道我可以将 ev
转换为兼容的委托,但我想知道如何记录该委托并将其从事件中删除?因为我读到匿名委托不能从 event
中删除,除非在注册时记录它(如(此问题)[Adding and Removing Anonymous Event Handler 中所述)。 Aslo,这样做同样一点也不优雅...
Func<FileSystemEventHandler, RenamedEventHandler> renameDelegate = (FileSystemEventHandler h) =>
{
return (object sender, RenamedEventArgs args) => h(sender, args);
};
var observable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
ev => { watcher.Changed += ev;
//registered delegate
watcher.Renamed += renameDelegate(ev);
},
ev => { watcher.Changed -= ev;
//this seems not to be identical with the one registered
watcher.Renamed -= renameDelegate(ev); });
);
那么我如何在同一个 Observable
中同时观察 Changed
和 Renamed
事件?
编辑 1
感谢@Enigmativity 的回答,我的最终代码如下(示例代码):
var o1 = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
ev => watcher.Changed += ev,
ev => watcher.Changed -= ev);
var o2 = Observable.FromEventPattern<RenamedEventHandler, RenamedEventArgs>(
ev => watcher.Renamed += ev,
ev => watcher.Renamed -= ev)
.Select(x => new System.Reactive.EventPattern<FileSystemEventArgs>(x.Sender, x.EventArgs));
var o = Observable.Merge(o1, o2);
var d = o.Throttle(TimeSpan.FromSeconds(5))
.Subscribe(
a => Console.WriteLine($"Watcher type:{a.EventArgs.ChangeType }, file:{a.EventArgs.Name }, sender: {a.Sender}"),
ex => Console.WriteLine("observer error:" + ex.ToString()),
() => Console.WriteLine("observer complete.")
操作方法如下:
var observable =
Observable
.Using(
() => new FileSystemWatcher() { Path = "d:\test" },
watcher =>
Observable
.Merge(
Observable
.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
ev => watcher.Changed += ev,
ev => watcher.Changed -= ev)
.Select(x => new
{
x.EventArgs.Name,
x.EventArgs.FullPath,
x.EventArgs.ChangeType,
OldName = (string)null,
OldFullPath = (string)null,
}),
Observable
.FromEventPattern<RenamedEventHandler, RenamedEventArgs>(
ev => watcher.Renamed += ev,
ev => watcher.Renamed -= ev)
.Select(x => new
{
x.EventArgs.Name,
x.EventArgs.FullPath,
x.EventArgs.ChangeType,
x.EventArgs.OldName,
x.EventArgs.OldFullPath
})));