如何在C#中的运行时更改IObservable Func谓词



我对动态数据和一般的反应式扩展世界是新手,我目前面临以下问题,我想在运行时通过使用动态数据包来更改IObservable<Func<T,bool>>谓词,从而在.NET(C#(中更改反应式扩展。

考虑到以下情况,我有一个DataGrid,其中一些列的类型为integer(比方说a、B、C(。此外,还有一个过滤器UI,用户可以在其中添加多个过滤器,如a==6或过滤器表达式的组合,如a==7||a==3||B==5等。因此,基本上,我返回Func<T, bool>委托的方法如下所示:

private Func<T, bool> FilterOnA(string id)
{
return n => n.Id == int.Parse(id);
}

以及数据管道中的Filter方法调用:

// sourceList is used to fill the ReadOnlyObservableCollection<T> while receiving data from an event pattern
sourceList.Connect()                        // SourceList<T>
.Filter(filterViewModel.FilterOnA)
.Bind(out _itemsBinding)          // private ReadOnlyObservableCollection<T>
.DisposeMany()
.Subscribe();

正如我上面提到的,用户应该能够添加/删除/修改,更重要的是,将过滤器表达式组合在一起。

由于动态的数据过滤器方法采用Func<T,bool>IObservable<Func<T,bool>>,因此一种可能的解决方案可能如下所示:

public IObservable<Func<T,bool>> Filter1 {get;} 
public IObservable<Func<T,bool>> Filter2 {get;}
public IObservable<Func<T,bool>> Filter3 {get;}
public IObservable<Func<T,bool>> FilterX {get;}
public IObservable<Func<T,bool>> AllFiltersCombined => Filter1.CombineLatest(Filter2,Filter3,FilterX, (f1,f2,f3,fx) => AggregatePredicatesAnd(f1,f2,f3,fx));

public static Func<T,Bool> AggregatePredicatesAnd(params Func<T,bool>[] predicates) 
{
return predicates.Aggregate<Func<T,bool>>((fa,fb) => (T t) => fa(t) && fb(t));
}

现在,我的问题是,如何用一种更通用的方式来写这篇文章?如何组合例如0 to n过滤器?不同的过滤器类型是什么,例如a<=7&amp;A!=5

您可以使用这里显示的ApplyFilters操作:

public static class Extensions
{
public static List<T> Apply<T>(this List<T> list, Action<List<T>> action)
{
action(list);
return list;
}
public static IObservable<T> ApplyFilters<T>(this IObservable<T> source, IObservable<Func<T, bool>> AddFilter, IObservable<Func<T, bool>> RemoveFilter)
{
// Project AddFilter to a func that adds a filter to a list of filters
var adding = AddFilter.Select(func => (Action<List<Func<T, bool>>>)(list => list.Add(func)));
// Project RemoveFilter to a func that removes a filter from a list of filters
var removing = RemoveFilter.Select(func => (Action<List<Func<T, bool>>>)(list => list.Remove(func)));
// Return an observable that...
return Observable
// ... merges the add and remove operations ...
.Merge(adding, removing)
// ... and applies them to an initially empty list ...
.Scan(new List<Func<T, bool>>(), (list, change) => list.Apply(change))
// ... and project every list change to a new observable
// by applying all operations to the source observable ...
.Select(list => list.Aggregate(source, (s, f) => s.Where(f)))
// ... and finally subscribing to the new observable
.Switch();
}
}
public class ViewModel
{
public IObservable<Item> _source;
public IObservable<Func<Item, bool>> _addFilter;
public IObservable<Func<Item, bool>> _removeFilter;
public ViewModel()
{
FilteredItems = _source.ApplyFilters(_addFilter, _removeFilter);
}
public IObservable<Item> FilteredItems { get; }
}
public class Item  {  }

限制:

  1. 未考虑Func<T, bool>等效性。您可能需要强键入每个筛选器函数,以确保能够正确地将其添加到筛选器的内部列表中/从中删除。

  2. 没有考虑分组&amp;和||操作(即(A == 7 && B == "Hello") || C == -1)(。如果这很重要,你肯定需要强烈键入过滤器(根据1(并添加一个组标识符。然后,在对可观察对象执行Aggregate之前,可以在列表中使用GroupBy

与ibeebs的答案相比,我还发现了另一种可能的解决方案。为了构建可能的过滤器组合,可以使用动态表达式库:https://github.com/zzzprojects/System.Linq.Dynamic/wiki/Dynamic-Expressions并创建这样的表达式:

Expression<Func<T, bool>> e2 = DynamicExpression.ParseLambda<T, bool>("Id == 7 or Id == 9");

或者更复杂的。

由于我在问题中提到用户可以通过UI创建过滤器,因此构建像"Id == 7 or Id == 9"这样的字符串表达式也没什么大不了的。

这样的CCD_ 11可以被简单地编译为CCD_。

相关内容

  • 没有找到相关文章

最新更新