![]() |
VOOZH | about |
dotnet add package ReactiveList --version 5.0.2
NuGet\Install-Package ReactiveList -Version 5.0.2
<PackageReference Include="ReactiveList" Version="5.0.2" />
<PackageVersion Include="ReactiveList" Version="5.0.2" />Directory.Packages.props
<PackageReference Include="ReactiveList" />Project file
paket add ReactiveList --version 5.0.2
#r "nuget: ReactiveList, 5.0.2"
#:package ReactiveList@5.0.2
#addin nuget:?package=ReactiveList&version=5.0.2Install as a Cake Addin
#tool nuget:?package=ReactiveList&version=5.0.2Install as a Cake Tool
👁 NuGet
👁 NuGet Downloads
👁 Build Status
ReactiveList is a high-performance, thread-safe observable collection library for .NET. It provides list, dictionary, sharded, indexed, and view-based collection types that publish change streams for UI binding, reactive workflows, live data processing, and low-allocation batch operations.
<p align="center"> <img src="Images/HeroImage.png" alt="ReactiveList V5 dual package configuration" width="500" /> </p>
ReactiveList V5.0.x introduces a dual package configuration and changes the base namespaces.
This is a breaking change from ReactiveList V4.x.x.
| V5 package | Dependency model | Base namespace | Scheduler type | Use when |
|---|---|---|---|---|
ReactiveList |
ReactiveUI.Primitives |
CP.Primitives.* |
ReactiveUI.Primitives.Concurrency.ISequencer |
You want the lean ReactiveUI.Primitives package without a System.Reactive dependency. |
ReactiveList.Reactive |
ReactiveUI.Primitives.Reactive and System.Reactive |
CP.Reactive.* |
System.Reactive.Concurrency.IScheduler |
You already use System.Reactive and want Rx scheduler conventions in public APIs. |
Do not mix the two package variants in the same pipeline casually. Their namespaces and scheduler conventions are deliberately different. If an application needs both, keep a clear boundary between the lean CP.Primitives.* code and the System.Reactive CP.Reactive.* code.
Lean primitives package:
dotnet add package ReactiveList --version 5.0.*
System.Reactive package:
dotnet add package ReactiveList.Reactive --version 5.0.*
The package dependencies are brought in automatically:
ReactiveList references ReactiveUI.Primitives.ReactiveList.Reactive references ReactiveUI.Primitives.Reactive, which references System.Reactive.Use only one variant unless you have a specific interop boundary.
using CP.Primitives;
using CP.Primitives.Collections;
using CP.Primitives.Core;
using CP.Primitives.Views;
using ReactiveUI.Primitives;
using ReactiveUI.Primitives.Concurrency;
Use this package when:
IObservable<T> without a direct System.Reactive dependency.ReactiveUI.Primitives.Concurrency.ISequencer.Sequencer.Default, Sequencer.Immediate, or SynchronizationContextSequencer.Current.ReactiveUI.Primitives.using CP.Reactive;
using CP.Reactive.Collections;
using CP.Reactive.Core;
using CP.Reactive.Views;
using ReactiveUI.Primitives.Reactive;
using System.Reactive.Concurrency;
Use this package when:
IScheduler.ImmediateScheduler.Instance, CurrentThreadScheduler.Instance, or Scheduler.Default.V4 code usually used CP.Reactive.* from the main package. In V5 you must choose the package variant first.
Use this path if you do not need System.Reactive scheduler types in your public API.
ReactiveList V5.0.x.CP.Reactive -> CP.Primitives
CP.Reactive.Collections -> CP.Primitives.Collections
CP.Reactive.Core -> CP.Primitives.Core
CP.Reactive.Views -> CP.Primitives.Views
CP.Reactive.Internal -> CP.Primitives.Internal
ReactiveUI.Primitives imports:using ReactiveUI.Primitives;
using ReactiveUI.Primitives.Concurrency;
using ReactiveUI.Primitives.Signals;
using CP.Primitives.Collections;
using ReactiveUI.Primitives.Concurrency;
var list = new ReactiveList<int>();
using var view = list.CreateView(Sequencer.Immediate, throttleMs: 0);
CP.Reactive.* NamespacesUse this path if you want the old CP.Reactive.* namespace shape and System.Reactive scheduler conventions.
ReactiveList.Reactive V5.0.x.CP.Reactive.* namespaces.ReactiveUI.Primitives.Concurrency.ISequencer schedulers with System.Reactive.Concurrency.IScheduler.using CP.Reactive.Collections;
using System.Reactive.Concurrency;
var list = new ReactiveList<int>();
using var view = list.CreateView(ImmediateScheduler.Instance, throttleMs: 0);
ReactiveUI.Primitives and System.Reactive can otherwise create ambiguous Subscribe calls.CP.Primitives.* for the lean package and CP.Reactive.* for the System.Reactive package.using CP.Primitives.Collections;
using CP.Primitives.Core;
using ReactiveUI.Primitives;
var orders = new ReactiveList<Order>();
using var subscription = orders.Stream.Subscribe(notification =>
{
if (notification.Action == CacheAction.Added && notification.Item is not null)
{
Console.WriteLine($"Added order {notification.Item.Id}");
}
});
orders.Add(new Order(1, 125.00m));
orders.AddRange([new Order(2, 40.00m), new Order(3, 75.00m)]);
public sealed record Order(int Id, decimal Amount);
using CP.Reactive.Collections;
using CP.Reactive.Core;
using System;
using System.Reactive.Concurrency;
var orders = new ReactiveList<Order>();
using var subscription = orders.Stream.Subscribe(notification =>
{
if (notification.Action == CacheAction.Added && notification.Item is not null)
{
Console.WriteLine($"Added order {notification.Item.Id}");
}
});
orders.Add(new Order(1, 125.00m));
using var view = orders.CreateView(ImmediateScheduler.Instance, throttleMs: 0);
public sealed record Order(int Id, decimal Amount);
using CP.Primitives.Collections;
var list = new ReactiveList<string>();
list.Edit(editor =>
{
editor.Add("alpha");
editor.Add("beta");
editor.Insert(1, "middle");
editor.Remove("alpha");
});
Edit batches collection mutations and emits one batch notification after the transaction completes.
ReactiveList does not require R3, but the lean ReactiveList package depends on ReactiveUI.Primitives, which packs the ReactiveUI.Primitives R3 bridge source generator as an analyzer. Do not add ReactiveUI.Primitives.R3Bridge.Generator directly.
To use R3:
dotnet add package ReactiveList --version 5.0.*
dotnet add package R3
Then import the generated bridge namespace:
using CP.Primitives.Collections;
using ReactiveUI.Primitives.R3Bridge;
var list = new ReactiveList<int>();
// System.IObservable<CacheNotify<int>> -> R3.Observable<CacheNotify<int>>
var r3Stream = list.Stream.AsR3Observable();
The source generator emits bridge methods only when the consumer assembly references the required R3 symbols:
| R3 symbol availability | Generated bridge methods |
|---|---|
R3.Observable<T> and System.IObservable<T> |
AsPrimitivesSignal<T>(this R3.Observable<T>), AsR3Observable<T>(this System.IObservable<T>) |
R3.Observable<T> and ReactiveUI.Primitives.Async.IObservableAsync<T> |
AsPrimitivesAsyncObservable<T>(this R3.Observable<T>), AsR3Observable<T>(this IObservableAsync<T>) |
R3Async.AsyncObservable<T> and IObservableAsync<T> |
AsPrimitivesAsyncObservable<T>(this R3Async.AsyncObservable<T>), AsR3AsyncObservable<T>(this IObservableAsync<T>) |
Use bridges at the edge of your application. Keep the internal pipeline in one model after conversion.
Example with an R3 filter stream:
using CP.Primitives.Collections;
using ReactiveUI.Primitives.Concurrency;
using ReactiveUI.Primitives.R3Bridge;
var list = new ReactiveList<Product>();
R3.Observable<Func<Product, bool>> r3Filter = GetFilterObservable();
var primitivesFilter = r3Filter.AsPrimitivesSignal();
using var view = list.CreateView(primitivesFilter, Sequencer.Immediate, throttleMs: 0);
static R3.Observable<Func<Product, bool>> GetFilterObservable() =>
R3.Observable.Return<Func<Product, bool>>(product => product.IsActive);
public sealed record Product(string Name, bool IsActive);
For System.Reactive-first projects, prefer ReactiveList.Reactive. Use R3 conversion at boundaries only if that assembly also references R3 and the required ReactiveUI.Primitives bridge symbols.
Every collection exposes a stream of cache notifications:
IObservable<CacheNotify<T>> Stream { get; }
The stream emits CacheNotify<T> values for single-item, batch, clear, move, update, and refresh operations.
CacheNotify<T> describes a collection change.
| Member | Meaning |
|---|---|
Action |
The CacheAction that occurred. |
Item |
The current item for single-item operations. |
Batch |
A pooled batch for batch operations. Dispose batches when using low-level APIs directly, or use AutoDisposeBatches. |
CurrentIndex |
Current item index when available. |
PreviousIndex |
Previous item index for move operations when available. |
Previous |
Previous value for update operations. |
CacheAction values:
AddedRemovedUpdatedMovedRefreshedClearedBatchOperationBatchAddedBatchRemovedChangeSet<T> is a compact IReadOnlyList<Change<T>> used for DynamicData-style processing.
Useful members:
CountAddsRemovesUpdatesMovesAsSpan()Dispose()Change<T> provides factory methods for CreateAdd, CreateRemove, CreateUpdate, CreateMove, and CreateRefresh.
ChangeReason values:
AddRemoveUpdateMoveRefreshClearReactiveList<T> is a thread-safe observable list implementing IList<T>, non-generic IList, IReadOnlyList<T>, INotifyCollectionChanged, INotifyPropertyChanged, and IDisposable.
Constructors:
new ReactiveList<T>();
new ReactiveList<T>(IEnumerable<T> items);
new ReactiveList<T>(T item);
Properties and streams:
| API | Description |
|---|---|
Count |
Current item count. |
Items |
Bindable ReadOnlyObservableCollection<T>. |
ItemsAdded |
Last added items. |
ItemsRemoved |
Last removed items. |
ItemsChanged |
Last changed items. |
Stream |
Unified IObservable<CacheNotify<T>>. |
Added |
IObservable<IEnumerable<T>> for added items. |
Removed |
IObservable<IEnumerable<T>> for removed items. |
Changed |
IObservable<IEnumerable<T>> for changed items. |
CurrentItems |
Emits snapshots on subscription and after changes. |
Version |
Atomic modification version. |
IsDisposed |
Disposal state. |
IsReadOnly, IsFixedSize, IsSynchronized |
Collection compatibility members. |
Mutation methods:
| API | Description |
|---|---|
Add(T) / Add(object?) |
Add one item. |
AddRange(IEnumerable<T>) |
Add multiple items. |
AddRange(ReadOnlySpan<T>) |
Add span data on modern TFMs. |
Insert(int, T) / Insert(int, object?) |
Insert one item. |
InsertRange(int, IEnumerable<T>) |
Insert multiple items. |
Remove(T) / Remove(object?) |
Remove one item. |
Remove(IEnumerable<T>) |
Remove multiple explicit items. |
RemoveAt(int) |
Remove by index. |
RemoveRange(int, int) |
Remove a contiguous range. |
RemoveMany(Func<T, bool>) |
Remove all matching items. |
Move(int, int) |
Move an item between indexes. |
Update(T, T) |
Replace an existing item. |
ReplaceAll(IEnumerable<T>) |
Replace the complete contents. |
Clear() |
Clear and notify. |
ClearWithoutDeallocation(bool notifyChange = true) |
Clear while retaining internal capacity. |
Edit(Action<IEditableList<T>>) |
Batch mutations and emit a single notification. |
Dispose() |
Release streams and internal resources. |
Read and copy methods:
| API | Description |
|---|---|
Indexer this[int] |
Get or set item by index. |
Contains(T) / Contains(object?) |
Check membership. |
IndexOf(T) / IndexOf(object?) |
Locate an item. |
CopyTo(T[], int), CopyTo(Array, int), CopyTo(Span<T>) |
Copy items. |
ToArray() |
Snapshot to array. |
AsSpan() |
Exposes a read-only span over current storage. Use only when no concurrent writes can occur. |
AsMemory() |
Snapshot as memory. |
GetEnumerator() |
Enumerate a safe snapshot. |
Reactive2DList<T> derives from ReactiveList<ReactiveList<T>> and models rows, grids, matrices, and nested collections.
Constructors:
new Reactive2DList<T>();
new Reactive2DList<T>(IEnumerable<IEnumerable<T>> items);
new Reactive2DList<T>(IEnumerable<ReactiveList<T>> items);
new Reactive2DList<T>(IEnumerable<T> items);
new Reactive2DList<T>(ReactiveList<T> item);
new Reactive2DList<T>(T item);
Additional methods:
| API | Description |
|---|---|
AddRange(IEnumerable<IEnumerable<T>>) |
Add multiple rows. |
AddRange(IEnumerable<T>) |
Add one row from values. |
AddToInner(int, T) |
Add one item to a row. |
AddToInner(int, IEnumerable<T>) |
Add multiple items to a row. |
GetItem(int, int) |
Read a cell. |
SetItem(int, int, T) |
Replace a cell. |
Insert(int, T) |
Insert a row containing one item. |
Insert(int, IEnumerable<T>) |
Insert a row from values. |
Insert(int, IEnumerable<T>, int) |
Insert values into an existing row. |
RemoveFromInner(int, int) |
Remove a cell. |
ClearInner(int) |
Clear a row. |
Flatten() |
Return all cells as a flat sequence. |
TotalCount() |
Count all cells. |
QuaternaryList<T> is a four-shard thread-safe observable collection for large data sets, lower allocation pressure, parallel-friendly operations, and secondary-index lookups.
Core APIs:
| API | Description |
|---|---|
Add(T) |
Add one item. |
AddRange(IEnumerable<T>) |
Add many items. |
Remove(T) |
Remove one item. |
RemoveRange(IEnumerable<T>) |
Remove many explicit items. |
RemoveMany(Func<T, bool>) |
Remove matching items. |
ReplaceAll(IEnumerable<T>) |
Replace all items. |
Edit(Action<ICollection<T>>) |
Batch edits. |
Clear() |
Clear all shards. |
Contains(T) |
Check membership. |
CopyTo(T[], int) |
Copy to array. |
Snapshot() |
Return an immutable point-in-time list. |
ToArray() |
Copy all items to an array. |
Stream |
Change notification stream. |
Count, Version, IsDisposed |
State and diagnostics. |
Secondary index APIs:
| API | Description |
|---|---|
AddIndex<TKey>(string, Func<T, TKey>) |
Add a named item index. |
GetItemsBySecondaryIndex<TKey>(string, TKey) |
Lookup by index key. |
ItemMatchesSecondaryIndex<TKey>(string, T, TKey) |
Test whether an item belongs to an index key. |
FilterBySecondaryIndex |
Stream changes that match one or more index keys. |
CreateViewBySecondaryIndex |
Create a live view for one or more index keys. |
CreateDynamicViewBySecondaryIndex |
Create a live view whose index keys come from an observable. |
QuaternaryDictionary<TKey, TValue> is a four-shard thread-safe observable dictionary for key-value caches, bulk writes, and value-indexed lookup.
Core APIs:
| API | Description |
|---|---|
Add(TKey, TValue) |
Add one pair. |
TryAdd(TKey, TValue) |
Add when absent. |
AddOrUpdate(TKey, TValue) |
Add or replace. |
AddRange(IEnumerable<KeyValuePair<TKey, TValue>>) |
Add many pairs. |
Remove(TKey) |
Remove by key. |
Remove(KeyValuePair<TKey, TValue>) |
Remove exact pair. |
RemoveKeys(IEnumerable<TKey>) |
Remove many keys. |
RemoveMany(Func<KeyValuePair<TKey, TValue>, bool>) |
Remove matching pairs. |
TryGetValue(TKey, out TValue) |
Lookup by key. |
Lookup(TKey) |
Lookup by key with a (HasValue, Value) tuple result. |
ContainsKey(TKey) |
Check key presence. |
Contains(KeyValuePair<TKey, TValue>) |
Check exact pair. |
Edit(Action<IDictionary<TKey, TValue>>) |
Batch edits. |
Clear() |
Clear all shards. |
CopyTo(KeyValuePair<TKey, TValue>[], int) |
Copy pairs. |
Keys, Values, indexer |
Dictionary members. |
Stream |
Change notification stream. |
Secondary index APIs:
| API | Description |
|---|---|
AddValueIndex<TIndexKey>(string, Func<TValue, TIndexKey>) |
Add a named value index. |
GetValuesBySecondaryIndex<TIndexKey>(string, TIndexKey) |
Lookup values by secondary key. |
ValueMatchesSecondaryIndex<TIndexKey>(string, TValue, TIndexKey) |
Test value/index membership. |
CreateViewBySecondaryIndex |
Create a live dictionary view for an index key. |
FilterBySecondaryIndex |
Stream matching dictionary changes. |
CreateDynamicViewBySecondaryIndex |
Create a live view from observable index keys. |
QuadList<T> and QuadDictionary<TKey, TValue> are lower-level shard containers used by the quaternary collections. They expose direct add, remove, clear, copy, capacity, enumeration, and dispose operations. Most application code should use QuaternaryList<T> or QuaternaryDictionary<TKey, TValue> instead.
Views are disposable live projections over collection streams. Dispose them when the UI or workflow no longer needs updates.
Common view members:
ItemsCountCollectionChangedPropertyChangedRefresh()ToProperty(Action<ReadOnlyObservableCollection<T>>)ToProperty(out ReadOnlyObservableCollection<T>)Dispose()| View | Purpose |
|---|---|
ReactiveView<T> |
Basic live filtered view from stream and snapshot. |
FilteredReactiveView<T> |
Static predicate filtered list view. |
DynamicFilteredReactiveView<T> |
Filter predicate is supplied by an observable. |
DynamicReactiveView<T> |
Query/filter based dynamic view over an IReactiveSource<T>. |
SortedReactiveView<T> |
Sorted live list view. |
GroupedReactiveView<T, TKey> |
Live IReadOnlyDictionary<TKey, IReadOnlyList<T>> groups. |
SecondaryIndexReactiveView<TKey, TValue> |
Live dictionary-value view using a named secondary index. |
DynamicSecondaryIndexReactiveView<T, TKey> |
Live list secondary-index view with observable keys. |
DynamicSecondaryIndexDictionaryReactiveView<TKey, TValue> |
Live dictionary secondary-index view with observable keys. |
using CP.Primitives;
using CP.Primitives.Collections;
using ReactiveUI.Primitives.Concurrency;
using ReactiveUI.Primitives.Signals;
var products = new QuaternaryList<Product>();
products.AddIndex("ByCategory", product => product.Category);
using var active = products.CreateView(product => product.IsActive, Sequencer.Default);
using var grouped = products.GroupBy(product => product.Category, Sequencer.Default);
using var indexed = products.CreateViewBySecondaryIndex("ByCategory", "Hardware", Sequencer.Default);
var query = new BehaviorSignal<string>("hardware");
using var search = products.CreateView(
query,
static (text, product) => product.Name.Contains(text, StringComparison.OrdinalIgnoreCase),
Sequencer.Default);
public sealed record Product(string Name, string Category, bool IsActive);
These operate on IObservable<CacheNotify<T>>.
| API | Description |
|---|---|
ToChange() |
Convert one notification to a Change<T>. |
WhereAction(CacheAction) |
Filter by action. |
WhereAdded() / WhereRemoved() |
Filter add/remove notifications. |
SelectItems() |
Select the single current item from matching notifications. |
SelectAllItems() |
Flatten single and batch item notifications. |
OnItemAdded() / OnItemRemoved() / OnItemUpdated() |
Convenience item streams. |
OnItemMoved() |
Stream move tuples with old and new index. |
OnCleared() |
Stream clear notifications. |
BufferNotifications(TimeSpan) |
Buffer notifications for a duration. |
ThrottleNotifications(TimeSpan) |
Throttle notification bursts. |
ObserveOnScheduler(...) |
Observe notifications on the selected scheduler/sequencer. |
TransformItems(Func<T, TResult>) |
Transform item payloads. |
FilterItems(Func<T, bool>) |
Filter item payloads. |
AutoDisposeBatches() |
Dispose pooled batches after observation. |
CountByAction() |
Count notifications by action. |
ToChangeSets() |
Convert notifications to ChangeSet<T> streams. |
These operate on collection streams and change sets.
| API | Description |
|---|---|
FilterDynamic(...) |
Apply observable predicates to list or dictionary notifications. |
WhereItems(Func<T, bool>) |
Filter notification items. |
WhereChanges(Func<Change<T>, bool>) |
Filter changes in change sets. |
WhereReason(ChangeReason) |
Filter changes by reason. |
SelectChanges(...) |
Project change sets or individual changes. |
OnAdd() / OnRemove() / OnUpdate() / OnMove() |
Stream item-level changes. |
GroupByChanges(Func<T, TKey>) |
Group changes by key. |
GroupingByChanges(Func<T, TKey>) |
Stream IGrouping<TKey, Change<T>>. |
SortBy(Func<T, TKey>) |
Sort change-set payloads. |
AutoRefresh(string?) |
Emit refreshes for property changes. |
AutoRefresh(Expression<Func<T, object>>) |
Typed property refresh helper. |
Connect() |
Connect an IReactiveSource<T> to change-set streams. |
CreateView(...) |
Create static, dynamic, query-driven, and unfiltered views. |
SortBy(...) |
Create sorted live views. |
GroupBy(...) |
Create grouped live views. |
These operate on QuaternaryList<T> and QuaternaryDictionary<TKey, TValue>.
| API | Description |
|---|---|
FilterBySecondaryIndex(...) |
Filter stream notifications by one or more secondary-index keys. |
CreateViewBySecondaryIndex(...) |
Create live views for one or more secondary-index keys. |
CreateDynamicViewBySecondaryIndex(...) |
Create live views whose index keys are supplied by an observable. |
| Interface | Purpose |
|---|---|
IReactiveSource<T> |
Base observable collection contract with Stream, enumeration, INotifyCollectionChanged, and disposal. |
IReactiveList<T> |
ReactiveList<T> contract: IList<T>, IList, IReadOnlyList<T>, IReactiveSource<T>, and property notifications. |
IQuaternaryList<T> |
Sharded list contract with indexing and batch edit support. |
IQuaternaryDictionary<TKey, TValue> |
Sharded dictionary contract with value indexing and batch edit support. |
IReactiveView<TView, TItem> |
Disposable live-view contract. |
IEditableList<T> |
Edit transaction surface used by ReactiveList<T>.Edit. |
IGroupedObservable<TKey, TElement> |
Observable grouping contract. |
ISecondaryIndex<T> |
Secondary-index contract. |
IResettable |
Reset contract for pooled internals. |
IQuad<T> |
Lower-level shard contract. |
| Type | Purpose |
|---|---|
CacheNotify<T> |
One collection notification. |
CacheAction |
Notification action enum. |
Change<T> |
One DynamicData-style change. |
ChangeReason |
Change reason enum. |
ChangeSet<T> |
Compact collection of changes. |
PooledBatch<T> |
Disposable pooled batch container. |
ReactiveGroup<TKey, T> |
Bindable group used by grouped views. |
SecondaryIndex<T, TKey> |
Named lookup index implementation. |
EditableListWrapperPool |
Pool configuration and rental for edit wrappers. |
PooledEditableListWrapper<T> |
Pooled edit wrapper used by transactions. |
| Package | Root | Collections | Core | Views |
|---|---|---|---|---|
ReactiveList |
CP.Primitives |
CP.Primitives.Collections |
CP.Primitives.Core |
CP.Primitives.Views |
ReactiveList.Reactive |
CP.Reactive |
CP.Reactive.Collections |
CP.Reactive.Core |
CP.Reactive.Views |
All public collection operations are designed for thread-safe use.
ReactiveList<T> uses lock-based synchronization for list and observable collection state.Reactive2DList<T> inherits the thread-safety model from ReactiveList<T>.QuaternaryList<T> and QuaternaryDictionary<TKey, TValue> use four internal shards and reader/writer locking to reduce contention for larger data sets.Use care with direct-memory APIs:
AsSpan() exposes current storage and should be used only when you can guarantee no concurrent writes.ToArray(), Snapshot(), or AsMemory() for defensive snapshots.ReactiveList is optimized for low-allocation notifications, pooled batches, sharded storage, and batch editing.
Use these patterns:
| Scenario | Recommendation |
|---|---|
| Multiple related edits | Use Edit(...) or AddRange(...) rather than many independent writes. |
| UI-bound views | Use CreateView, SortBy, or GroupBy with a UI scheduler/sequencer and a throttle. |
| Large list batches | Use QuaternaryList<T>. |
| Key-value cache workloads | Use QuaternaryDictionary<TKey, TValue>. |
| Frequent category or value lookups | Add a secondary index and query with index APIs. |
| Notification bursts | Use BufferNotifications, ThrottleNotifications, or view throttling. |
| Pooled batch handling | Use AutoDisposeBatches when observing low-level batches manually. |
Measured benchmark highlights from the V5 work:
| Scenario | Result |
|---|---|
QuaternaryList<T> vs DynamicData SourceList<T> AddRange |
Lower allocations and faster large-batch throughput at 1,000 and 10,000 item sizes. |
QuaternaryDictionary<TKey, TValue> vs DynamicData SourceCache<TValue, TKey> AddRange |
Faster and lower allocation at all measured sizes. |
| Observable isolation | Core collection operations remain independent from subscriber-side work. |
The library targets the shared CoreTargetFrameworks configured for the repository:
net8.0net9.0net10.0net11.0net462, net472, net48, net481, and matching Windows TFMs are included.Native AOT compatibility is enabled for compatible modern .NET target frameworks.
The V5 dual package configuration has been verified locally with:
dotnet restore src\ReactiveList.sln
dotnet build src\ReactiveList.sln -c Release --no-restore -v quiet
dotnet test src\ReactiveList.sln -c Release --no-build --no-restore
The full TUnit run passed across the solution with 2,901 tests, 0 failed, and 0 skipped. The targeted MTP Cobertura coverage run reported 100.00% line coverage for the ReactiveList package.
This project is licensed under the MIT License. See for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net8.0-windows10.0.19041 net8.0-windows10.0.19041 is compatible. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net9.0-windows10.0.19041 net9.0-windows10.0.19041 is compatible. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. net10.0-windows10.0.19041 net10.0-windows10.0.19041 is compatible. net11.0 net11.0 is compatible. net11.0-windows10.0.19041 net11.0-windows10.0.19041 is compatible. |
| .NET Framework | net462 net462 is compatible. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 is compatible. net48 net48 is compatible. net481 net481 is compatible. |
Showing the top 3 NuGet packages that depend on ReactiveList:
| Package | Downloads |
|---|---|
|
CrissCross.WPF.UI
A Reactive Navigation Framework for ReactiveUI |
|
|
CrissCross.WPF.Plot
A Reactive Navigation Framework for ReactiveUI |
|
|
CrissCross.Avalonia.UI
A Reactive Navigation Framework for ReactiveUI |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.0.2 | 0 | 6/18/2026 |
| 4.0.48 | 147 | 5/22/2026 |
| 4.0.35 | 419 | 5/4/2026 |
| 4.0.16 | 776 | 3/8/2026 |
| 4.0.4 | 156 | 2/5/2026 |
| 4.0.2 | 133 | 2/4/2026 |
| 3.0.5 | 195 | 1/13/2026 |
| 3.0.2 | 157 | 1/11/2026 |
| 2.4.5 | 421 | 12/7/2025 |
| 2.4.4 | 267 | 12/7/2025 |
| 2.3.2 | 360 | 10/6/2025 |
| 2.2.1 | 648 | 6/12/2025 |
| 2.2.0 | 332 | 1/28/2025 |
| 2.1.0 | 398 | 10/13/2024 |
| 2.0.2 | 406 | 5/13/2024 |
| 2.0.1 | 239 | 5/13/2024 |
| 2.0.0 | 226 | 5/2/2024 |
| 1.2.0 | 318 | 4/26/2024 |
Compatability with Net 8 / 9 / 10 and netstandard2.0