这是我最终建立的。它对我来说工作得很好。第一部分是计算和报告两组之间差异的通用类。
public class SetComparison<T>
{
private Lazy<IImmutableSet<T>> _added;
private Lazy<IImmutableSet<T>> _removed;
private Lazy<IImmutableSet<T>> _intersection;
public SetComparison(IEnumerable<T> previous, IEnumerable<T> current)
{
if (previous == null) throw new ArgumentNullException(nameof(previous));
if (current == null) throw new ArgumentNullException(nameof(current));
Previous = previous.ToImmutableHashSet();
Current = current.ToImmutableHashSet();
_added = new Lazy<IImmutableSet<T>>(() => Current.Except(Previous));
_removed = new Lazy<IImmutableSet<T>>(() => Previous.Except(Current));
_intersection = new Lazy<IImmutableSet<T>>(() => Current.Intersect(Previous));
}
public IImmutableSet<T> Previous { get; }
public IImmutableSet<T> Current { get; }
public IImmutableSet<T> Added => _added.Value;
public IImmutableSet<T> Removed => _removed.Value;
public IImmutableSet<T> Intersection => _intersection.Value;
}
这是一个通用的运营商,如F#成对采取序列,并把它变成一系列重叠的项目配对的。
public static IObservable<TResult> Pairwise<TSource, TResult>(
this IObservable<TSource> source,
Func<TSource, TSource, TResult> resultSelector) =>
source.Scan(
(default(TSource), default(TSource)),
(pair, current) => (pair.Item2, current))
.Skip(1)
.Select(p => resultSelector(p.Item1, p.Item2));
而这现在成对的两组。
public static IObservable<SetComparison<T>> PairwiseSetComparison<T, TCollection>(this IObservable<TCollection> source) where TCollection : IEnumerable<T> =>
source
.Pairwise((a, b) => new SetComparison<T>(a, b));
public static IObservable<SetComparison<T>> PairwiseSetComparison<T>(this IObservable<ImmutableArray<T>> source) =>
source.Pairwise((a, b) => new SetComparison<T>(a, b));
最后这一点,
public static IObservable<TResult> Merge<TResult, T>(this IObservable<SetComparison<T>> source, Func<T, IObservable<TResult>> result) =>
source
.Publish(s =>
{
var additions = s.SelectMany(i => i.Added);
var removals = s.SelectMany(i => i.Removed);
return
additions
.Select(add => result(add).TakeUntil(removals.Where(rem => rem.Equals(add))))
.Merge();
});
所以现在当我想订阅了仅在当前设置,我做这样的事情观测...
_items
.PairwiseSetComparison()
.Merge(i => i.Delete.Select(_ => i))
.Subscribe(i=> /* user clicked Delete on item i */)
完成这一切的另一种方法是在用户调用它时,让列表中的每个项目上的Delete ICommand实际运行一些委托。这样,我不必在命令被调用时实际订阅。尽管如此,我更愿意将我的清单中的物品完全不知道他们的周围环境。
你能解释一下为什么你在'IObservable>'中有'ImmutableList',而不仅仅是'IObservable '? –
Enigmativity
在我看来,如果您要为整个当前列表推送每个可观察值的值,那么您只需要查看该项目是否从以前推送的项目中缺失 - 无需“IObservable Delete”知道该项目被删除时。你能帮忙解释一下吗? –
Enigmativity
列表中的每个项目都是带有Edit,MoveUp,MoveDown和Delete等命令的视图模型 - 删除一个令您感到困惑。我想知道用户何时点击列表中任何特定项目的MoveDown。该列表经常随着用户添加和删除项目而发生变化,我只想侦听与列表中当前项目相关的事件。 – JustinM