将同步 "foreach item in IEnumerable" 转换为等效的异步操作

Convert synchronous "foreach item in IEnumerable" to equivalent asynchronous operation

目前我在一个 MVVM 项目中有两个 classes:

代码如下

虽然文件加载是并行进行的,但我只能在加载所有文件后填充 ObservableCollection,这当然是一种糟糕的方法。

我的目标是在调用后立即将 Populate/GetItems 转换为 return 的东西,加载的项目将 "pop up" 在 ObservableCollection 中作为他们一加载。

我能想到一些类似 Parallel.ForEachIObservable 事件的东西,但我不得不承认我对可能的替代方案感到迷茫。

class Presenter
{
    public ObservableCollection<TVM> ItemsVM {get;}
        = new ObservableCollection<TVM>();

    public Loader _loader 
    = new Loader(some_well_known_directory_path);

    void Populate()
    {
        foreach (T t_item in _loader.GetItems())
        {
            ItemsVM.Add(new TVM(t_item));
        }
    }
}

class Loader
{
    readonly string _path;

    public Loader(string path)
    {
        _path = path;
    }

    public IEnumerable<T> GetItems()
    {
        var result_list = new List<T>();

        Parallel.ForEach(Directory.GetFiles(_path), fname =>
        {
            try
            {
                result_list.Add(T.Load(fname));
            }
            catch (Exception e)
            {
                logger.Warn(e.Message);
            }
        });

        return result_list;
    }
}

这正是 Rx (System.Reactive) 适合的情况。

试试这个:

class Presenter
{
    public ObservableCollection<TVM> ItemsVM { get; }
        = new ObservableCollection<TVM>();

    public Loader _loader
        = new Loader(some_well_known_directory_path);

    void Populate()
    {
        _loader
            .GetItems()
            .Subscribe(t_item => ItemsVM.Add(new TVM(t_item)));
        }
    }
}

class Loader
{
    readonly string _path;

    public Loader(string path)
    {
        _path = path;
    }

    public IObservable<T> GetItems()
    {
        return
            Observable
                .Defer(() =>
                    Directory
                        .EnumerateFiles(_path)
                        .ToObservable()
                        .SelectMany(fname => Observable.Start(() => T.Load(fname)));
    }
}