簡體   English   中英

如何在運行時更改 IObservable Func 謂詞 C#

[英]How to change IObservable Func predicates at runtime in C#

我是動態數據的新手,一般來說是反應式擴展世界,我目前面臨以下問題,我想在運行時通過使用動態數據 package 更改IObservable<Func<T,bool>>謂詞以及 .NET (C#) 中的響應式擴展。

考慮到以下情況,我有一個DataGrid ,其中一些列的類型為integer ,比方說A,B,C 此外,還有一個過濾器 UI,用戶可以在其中添加多個過濾器,如A == 6或過濾器表達式的組合,如A == 7 || 一個 == 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();

正如我上面提到的,用戶應該能夠添加/刪除/修改,更重要的是將過濾器表達式組合在一起。

由於動態數據 Filter 方法采用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 && 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. 沒有考慮分組 && 和 || 操作(即(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"這樣的字符串表達式並不是什么大問題。

這樣的Expression可以簡單地編譯為Func<T, bool>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM