Table of Contents

One of the options available in the reactive ecosystem is the ReactiveCompositeCollections project by Brad Phelan which introduces a new ICompositeCollection<T> that works just like you would expect with LINQ. You can use Select, SelectMany, Where just like with IEnumerable<T> or IObservable<T> and the result of all these operators is another ICompositeCollection<T>

The library lives at Reactive Composite Collections (github) and is available from NuGet at Reactive Composite Collections (nuget)

Example

Here's a unit test that models a typical scenario:

  • a filter that a user can update via some UI binding.
  • a set of source data updated at runtime and needs to be combined
  • we wish to create a new dynamic list composed from the filter and the source lists.
public class FilterHolder : ReactiveObject
{
    private Func<int,bool> _Filter;
    public Func<int,bool> Filter { get => _Filter; set => this.RaiseAndSetIfChanged( ref _Filter, value ); }
}


[Fact]
public void DynamicFilterWithRxUIShouldWork()
{
    var sourceList0 = new CompositeSourceList<int>();
    var sourceList1 = new CompositeSourceList<int>();

    var filter = new FilterHolder {Filter = v => v > 5};

    // Using LINQ we can express the intent of the composition
    // and filtering very succinctly and using an API that
    // is consistent with IEnumerable and RX Extensions
    var target =
        from fn in filter.WhenAnyValue( p=>p.Filter )
        from s in new [] {sourceList0,  sourceList1 }.Concat()
        where fn(s)
        select s;

    sourceList0.AddRange( new []{0,1,2,3,4,5,6,7,8,9,10} );

    // Convert to an observable collection for testing purposes
    using (var oc = target.CreateObservableCollection( EqualityComparer<int>.Default ))
    {
        // Set the filter to be everything greater than 5
        oc.Should().Equal( 6, 7, 8, 9, 10 );
        sourceList0.Clear();
        oc.Should().Equal();

        sourceList0.AddRange( new []{0,1} );
        sourceList1.AddRange( new []{9,10} );

        oc.Should().Equal( 9, 10);

        // Set the filter to be everything less than 5
        filter.Filter =  v=>v<5;
        oc.Should().Equal( 0, 1);
    }
}

For more details head on over to Reactive Composite Collections (github)