将同步 "foreach item in IEnumerable" 转换为等效的异步操作
Convert synchronous "foreach item in IEnumerable" to equivalent asynchronous operation
目前我在一个 MVVM 项目中有两个 classes:
Presenter
class,它有一个 ObservableCollection<T>
和一个从 Loader
class 加载的项目填充它的操作;
Loader
class 本身,使用 GetItems()
操作反序列化在给定目录中找到的文件。
代码如下
虽然文件加载是并行进行的,但我只能在加载所有文件后填充 ObservableCollection,这当然是一种糟糕的方法。
我的目标是在调用后立即将 Populate
/GetItems
转换为 return 的东西,加载的项目将 "pop up" 在 ObservableCollection 中作为他们一加载。
我能想到一些类似 Parallel.ForEach
、IObservable
事件的东西,但我不得不承认我对可能的替代方案感到迷茫。
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)));
}
}
目前我在一个 MVVM 项目中有两个 classes:
Presenter
class,它有一个ObservableCollection<T>
和一个从Loader
class 加载的项目填充它的操作;Loader
class 本身,使用GetItems()
操作反序列化在给定目录中找到的文件。
代码如下
虽然文件加载是并行进行的,但我只能在加载所有文件后填充 ObservableCollection,这当然是一种糟糕的方法。
我的目标是在调用后立即将 Populate
/GetItems
转换为 return 的东西,加载的项目将 "pop up" 在 ObservableCollection 中作为他们一加载。
我能想到一些类似 Parallel.ForEach
、IObservable
事件的东西,但我不得不承认我对可能的替代方案感到迷茫。
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)));
}
}