SkillAgentSearch skills...

Rx.Net.Plus

Smart Reactive Extensions

Install / Use

/learn @ReactiveSoftware/Rx.Net.Plus
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Rx.Net.Plus

Table of content

Introduction

ReactiveX gains popularity and is widely used in several platforms and languages.

Following is an excerpt of Rx.Net Brief Intro :

"The Reactive Extensions (Rx) is a library for composing asynchronous and event-based programs using observable sequences and LINQ-style query operators. Using Rx, developers represent asynchronous data streams with Observables, query asynchronous data streams using LINQ operators, and parameterize the concurrency in the asynchronous data streams using Schedulers.

Simply put, Rx = Observables + LINQ + Schedulers."

If you have used Rx.Net (System.Reactive), you probably already wished to turn regular variable (like int, bool ) to become reactive.

What do we mean? We would like to:

  1. Be notified asynchronously whenever the value is changed (push model vs pull model)
  2. Connect variables to observable sources (be an observer) and utilize LINQ semantics
  3. Avoid repetitive notification of same value (as it doesn't matter with regular variables)
  4. Be able to synchronously get value of reactive variables using regular c# variable semantics. Compare them to other variables\constants, convert them to another type...

Hence, we could state that Rx.Net.Plus will lead to the following formula:

Rx.Net.Plus = Rx.Net + Observers + classic (pull model) c# semantics.

Rx.Net.Plus is a small but smart library which introduces two new types for this purpose (+ several extension methods):

| Type | Purpose | | :--------------- | ------------------------------------------------------------ | | RxVar | supersede basic types (as int, bool...) | | RxProperty | Support of MVVM to replace view-model properties (NotifyPropertyChanged pattern) |

RxVar

Basics

Let's start with an example:

Suppose you have in your code, some status of a connection named isConnected.

It may be defined as following:

bool IsConnected { get; set; }

You may want to react to change of connection status. One way is to poll this status periodically.

ReactiveX introduces the push model extending the Observer pattern.

One have to define an observable and update its state.

Other have to listen to events related to this observable as following:

IObservable<bool> IsConnected { get; set; }
....
IsConnected.Subscribe (_isConnected => _isConnected ? doSomething() : doAnotherThing());

Some questions arrive:

  1. How do we create this observable in a simple and straightforward way?
  2. How do we update the state of the observable?
  3. How can we use it as an ordinary variable - by polling its values - if (IsConnected) doSomething() ?
  4. How can we chain information from another source to update the IsConnected status?

The answer is: Rx.Net.Plus !!

With Rx.Net.Plus, it is super simple to define this kind of variable.

 var isConnected = false.ToRx(); // Create a reactive variable

We can easily update its state.

isConnected.Value = true;

Suppose we have a <u>sequential</u> algorithm, no problem to write this kind of code:

if (isConnected)		// Note we don't use .Value of isConnected
{
	StartWork();
}
else
{
	StopWork();
}

Let's say, connectionStatus is of type Observable

IObservable<bool> connectionStatus;

we can write:

connectionStatus.Subscribe (isConnected);

or using Rx.Net.Plus semantics:

	isConnected.ListenTo (connectionStatus);
or
	connectionStatus.RedirectTo (isConnected);
or
	connectionStatus.Notify (isConnected);

Rx.Net.Plus provides full comparison and equality support:

var anotherRxBool = true.ToRx();

if (isConnected == anotherRxBool)
{
	// Do some action
}

With primitive types (int, double...)

var intRx = 10.ToRx();               // Create a rxvar

if (intRx > 5)
{
	// React !!
}

RxVar could be used as part of state machines, and instead of polling statuses, flags, counters...

Just react upon change in this manner:

isConnected.When(true).Notify (v => reactToEvent());

It could be used for storing application information:

class SystemInfo
{
    RxVar<DateTime> CurrentTime;
    RxVar<bool>		AreHeadphonesConnected;
}
...

    systemInfo.CurrentTime.Notify (dt => DisplayToScreen (dt));	// Reactive !
....
   
   DateTime deadlineDate;
   if (systemInfo.CurrentTime > deadlineDate)					// Classic polling !
   {
       SendNotification();
   }

Note that RxVar behaves exactly as a classic variable. Therefore, as for classic variable, in case it is not initialized the value will be the default, RxVar will also publish the default value on subscription.

One option is to use the IgnoreNull* extension to avoid receiving the null value, or use Skip(1) to skip first value.

RxVar implements the following interfaces:

ISubject, IConvertible, IDisposable, IComparable, IEquatable, ISerializable

Comparison

By default, RxVar uses for its comparisons the default comparer of the generic type used

Comparer<T>.Default

In case a specific comparer is needed, RxVar provides the SetComparer method to specify it.

Boolean Operators

RxVar has the following 'pseudo' boolean operators: True, False, Not for comparison

if (isConnected.Not) equivalent if (! isConnected)

Distinct mode

By default, RxVar propagates its data (on new value assignment) only when a new distinct value is set.

That means that if some observer is subscribed to RxVar and the same value is assigned to RxVar, it will not be published.

In order to allow every update to be propagated, RxVar provide the following property:

IsDistinctMode

Note: distinct mode may be changed at any time even after subscription of observers.

ReadOnlyRxVar

RxVar can be published as read-only, similarly to IReadOnlyList concept for arrays.

This allows using of RxVar to be used without caring of being modified outside.

var rxVar = 10.ToRxVar();
var roRxVar = (IReadOnlyRxVar<int>)rxVar;
roRxVar.Value = 30;		// Won't compile !!!
rxVar.Value = 20;		// Compile
var val = roRxVar.Value;		// val is equal to 20

Rx.Net.Plus also offers a ToReadOnlyRxVar (similar to ToReadOnlyList method) method to convert a rw RxVar to a read-only RxVar which allows regular variable syntax:

var rxVar = 10.ToRxVar();
var roRxVar = rxVar.ToReadOnlyRxVar();
Assert.True(roRxVar > 5);		// This syntax is unavailable when using IReadOnlyRxVar<int> casting

Disposing

Rx.Net.Plus provides a base class which implements IDisposable, called DisposableBaseClass.

DisposableBaseClass has a built-in CancellationToken used by RxVar and RxProperty to automatically unsubscribe (in case they are used as observers) on disposing.

This is very convenient as there no need to handle IDisposable...when subscribing RxVar to observables.

The following method utilizes automatic un-subscription

  • ListenTo(IObservable<T> observable)
// Classic style
IDisposable subscription = observable.Subscribe (rxVar);
subscription.Dispose();

// Thanks to DisposabeBaseClass (used by RxVar)
rxVar.ListenTo (observable);
....
// RxVar is automatically unsubscribed from observable when disposed

Serialization

RxVar supports standard serialization (have been tested for binary, xml, Json formats).

The following fields are serialized: Value, IsDistinct.

Json Flat Serialization

What is Json "flat" serialization?

let's give an example. The following is part of the Test module in the solution.

    public class Info
    {
        public string Title { get; set; } = "Mr";
        public double Height { get; set; } = 76.5;
    }

	public class User
    {
        public RxVar<string> Name = "John".ToRxVar();
        public RxVar<bool> IsMale = true.ToRxVar();
        public RxVar<int> Age = 16.ToRxVar();
        public RxVar<Info> InfoUser = new Info().ToRxVar();

        public User()
        {
            Name.IsDistinctMode = false;
        }
    }

Normal Json serialization will output:

{
  "Name": {
    "IsDistinctMode": false,
    "Value": "John"
  },
  "IsMale": {
    "IsDistinctMode": true,
    "Value": true
  },
  "Age": {
    "IsDistinctMode": true,
    "Value": 16
  },
  "InfoUser": {
    "IsDistinctMode": true,
    "Value": {
      "Title": "Mr",
      "Height": 76.5
    }
  }

With flat serialization:

{
  "Name": "John",
  "IsMale": true,
  "Age": 16,
  "InfoUser": {
    "Title": "Mr",
    "Height": 76.5
  }
}

Json flat serialization is available through a dedicated Nuget package.

In order to apply flat serialization, follow these steps:

  1. Add a reference to Rx.Net.Plus.Json package.

  2. Call once the following method to apply this serialization style:

RxVarFlatJsonExtensions.RegisterToJso

Related Skills

View on GitHub
GitHub Stars37
CategoryDevelopment
Updated4mo ago
Forks4

Languages

C#

Security Score

72/100

Audited on Nov 18, 2025

No findings