如何创建一个“Observable”来观察“FileSystemWatcher”中的“Renamed”和“Changed”事件

mos*_*aka 1 filesystemwatcher system.reactive .net-core

我想创建一个Reactive Observable,它可以同时观察Renamed和。Changed

我正在监视文件夹中是否有已修改和重命名的文件FileSystemWatcher。我只想在事件稳定下来后处理该事件(因为有时Changed事件可能会引发多次)。所以我选择Throttle.net的功能Reactive Extension

我可以通过观察单个Changed事件来完成这项工作,但无法弄清楚如何ChangedRenamed单个Observable.

这是我为单个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.")
                );

Run Code Online (Sandbox Code Playgroud)

但是当我想观看这两个事件时,VS 告诉我FileSystemEventHandlerRenamedEventHandler不兼容(尽管RenamedEventArgs可以安全地转换为FileSystemEventArgs):

var observable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
                            ev => { 
                            watcher.Changed += ev; 
                            //Error
                            watcher.Renamed += ev; 
                            },
                            ev => { 
                            watcher.Changed -= ev; 
                            //Error
                            watcher.Renamed -= ev; 
                            });

Run Code Online (Sandbox Code Playgroud)

我知道我可以将 转换ev为兼容的 delegate ,但我想知道如何记录该委托并将其从事件中删除?因为我读到匿名委托不能被删除,event除非在注册时记录它(如(这个问题)[添加和删除匿名事件处理程序]中所述)。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); });
                );
Run Code Online (Sandbox Code Playgroud)

那么我怎样才能同时观察Changed和事件呢?RenamedObservable

编辑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.")
Run Code Online (Sandbox Code Playgroud)

Eni*_*ity 5

操作方法如下:

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
                            })));
Run Code Online (Sandbox Code Playgroud)