com.ges.tinyreactive 1.3.13

dotnet add package com.ges.tinyreactive --version 1.3.13
                    
NuGet\Install-Package com.ges.tinyreactive -Version 1.3.13
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="com.ges.tinyreactive" Version="1.3.13" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="com.ges.tinyreactive" Version="1.3.13" />
                    
Directory.Packages.props
<PackageReference Include="com.ges.tinyreactive" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add com.ges.tinyreactive --version 1.3.13
                    
#r "nuget: com.ges.tinyreactive, 1.3.13"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package com.ges.tinyreactive@1.3.13
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=com.ges.tinyreactive&version=1.3.13
                    
Install as a Cake Addin
#tool nuget:?package=com.ges.tinyreactive&version=1.3.13
                    
Install as a Cake Tool

TinyReactive

A lightweight reactive programming library for C#, optimized for use in Unity and other .NET environments. It provides a convenient toolkit for working with reactive data and events.

Key Features:

  • Notification of all subscribers when data changes
  • Use of the Unload collection for automatic unsubscribe and prevention of memory leaks
  • Support for passing unmanaged data by reference
  • Serialization to a base data format

Table of Contents

Installation

You should replace the "1.0.0" version shown in the examples with the current or available version!

Unity (OpenUPM or TGZ)

This package is available on OpenUPM for Unity.

Project/Packages/manifest.json:

{
  "dependencies": {
    "com.ges.tinyreactive": "1.0.0"
  },
  "scopedRegistries": [
    {
      "name": "package.openupm.com",
      "url": "https://package.openupm.com",
      "scopes": [
        "com.ges"
      ]
    }
  ]
}

It is also available in .tgz format in the current releases. After downloading, place the .tgz archive in your project's Packages folder, and add a reference to it in your manifest.json file.

Project/Packages/manifest.json:

{
  "dependencies": {
    "com.ges.tinyreactive": "file:com.ges.tinyreactive-1.0.0.tgz"
  }
}

NuGet - Without Unity dependency

To install from NuGet, there is a library without a Unity dependency.

<PackageReference Include="com.ges.tinyreactive" Version="1.0.0" />

Usage

Observed<T>

Allows tracking changes to a T value.

// Create Observed field
Observed<int> counter = new Observed<int>(100);

// Add listeners
counter.AddListener(ListenValue);
counter.AddListener(ListenValueChange);
counter.AddListener(ListenChange);

// Get current value
Console.WriteLine($"Counter current value: {counter.value}");

// Change value
counter.Set(90);

// Will be ignored because the current value is already 90
counter.TrySet(90);

// Change value without invoke listeners
counter.SetSilent(60);

// Remove listeners
counter.RemoveListener(ListenValue);
counter.RemoveListener(ListenValueChange);
counter.RemoveListener(ListenChange);

// Change value without any listeners
counter.Set(0);

// Listen value change
void ListenValue(int newValue) {
	Console.WriteLine($"Counter changed: {newValue}");
}

// Listen value change with current value
void ListenValueChange(int currentValue, int newValue) {
	Console.WriteLine($"Counter changed: from {currentValue} to {newValue}");
}

// Listen any value change
void ListenChange() {
	Console.WriteLine("Counter changed");
}
Counter current value: 100
Counter changed: 90
Counter changed: from 100 to 90
Counter changed

InputListener and InputListener<T>

A trackable event without storing the current value.

// Create InputListener field
InputListener inputEvent = new InputListener();

// Add listeners
inputEvent.AddListener(ListenChange);

// Send event
inputEvent.Send();

// Remove listeners
inputEvent.RemoveListener(ListenChange);

// Listen any change
void ListenChange() {
	Console.WriteLine("Input Event");
}
Input Event

Variants with additional parameters are also available.

// Create InputListener field
InputListener<int> inputEvent = new InputListener<int>();

// Add listeners
inputEvent.AddListener(ListenValue);
inputEvent.AddListener(ListenChange);

// Send event
inputEvent.Send(10);

// Remove listeners
inputEvent.RemoveListener(ListenValue);
inputEvent.RemoveListener(ListenChange);

// Listen value change
void ListenValue(int newValue) {
	Console.WriteLine($"Input Event: {newValue}");
}

// Listen any change
void ListenChange() {
	Console.WriteLine("Input Event");
}
Input Event: 10
Input Event

InputChanger<T>

Exists for tracking and modifying unmanaged values.

// Create InputChanger field
InputChanger<int> changeEvent = new InputChanger<int>();

// Add listeners
changeEvent.AddListener(ValueModify);

// Change value
int currentValue = 100;
changeEvent.Send(ref currentValue);
Console.WriteLine($"Changed first: {currentValue}");

// Remove listeners
changeEvent.RemoveListener(ValueModify);

// Change value without any listeners
changeEvent.Send(ref currentValue);
Console.WriteLine($"Changed second: {currentValue}");

// Listen value change
void ValueModify(ref int value) {
	value += 10;
}
Changed first: 110
Changed second: 110

ObservedList<T>

Tracks the addition and removal of values in a List<T>, as well as its clearing.

// Create ObservedList field
ObservedList<int> values = new ObservedList<int>();

// Add listeners
values.AddOnAddListener(OnValueAdd);
values.AddOnRemoveListener(OnValueRemove);

// Change values
values.Add(15);
values.Add(25);
values.Remove(15);
values.Add(40);

Console.WriteLine($"Current values: {values.Count}");

foreach(int item in values) {
	Console.WriteLine($"Value: {item}");
}

// Remove listeners
values.RemoveOnAddListener(OnValueAdd);
values.RemoveOnRemoveListener(OnValueRemove);

// Listen value add
void OnValueAdd(int value) {
	Console.WriteLine($"Added: {value}");
}

// Listen value add
void OnValueRemove(int value) {
	Console.WriteLine($"Removed: {value}");
}

Added: 15
Added: 25
Removed: 15
Added: 40

Current values: 2
Value: 25
Value: 40

ObservedDictionary<TKey, TValue>

Tracks the addition and removal of values in a Dictionary<TKey, TValue>.

// Create ObservedDictionary field
ObservedDictionary<string, int> values = new ObservedDictionary<string, int>();

// Add listeners
values.AddOnAddListener(OnValueAdd);
values.AddOnRemoveListener(OnValueRemove);

// Change values
values.Add("Key1", 15);
values.Add("Key2", 25);
values.Add("Key3", 35);

values.Remove("Key1");
values["Key2"] = 40; // Triggers Remove for old value, then Add for new

// Get values by key
if (values.TryGetValue("Key2", out int foundValue)) {
	Console.WriteLine($"Found: {foundValue}");
}

// Batch remove by values
values.RemoveRange(new List<int> { 40 });

Console.WriteLine($"Current values: {values.Count}");

foreach(KeyValuePair<string, int> item in values) {
	Console.WriteLine($"Pair: {item.Key}:{item.Value}");
}

// Remove listeners
values.RemoveOnAddListener(OnValueAdd);
values.RemoveOnRemoveListener(OnValueRemove);

// Listen value add
void OnValueAdd(int value) {
	Console.WriteLine($"Added: {value}");
}

// Listen value remove
void OnValueRemove(int value) {
	Console.WriteLine($"Removed: {value}");
}
Added: 15
Added: 25
Added: 35
Removed: 15
Removed: 25
Added: 40
Found: 40
Removed: 40
Current values: 1
Pair: Key3:35

Tracking a specific type of value.

// Create ObservedDictionary field
ObservedDictionary<string, object> values = new ObservedDictionary<string, object>();
UnloadPool unload = new UnloadPool();

// Add listeners
values.AddOnAddListenerValue<int>(OnIntValueAdd, unload);
values.AddOnAddListenerValue<string>(OnStringValueAdd, unload);

// Change values
values.Add("Key1", 15);
values.Add("Key2", "Hello");
values.Add("Key3", "World");
values.Add("Key4", true);

Console.WriteLine($"Current values: {values.Count}");

// Remove listeners
unload.Unload();

// Listen value add, with type-specific filter
void OnIntValueAdd(int value) {
	Console.WriteLine($"Int added: {value}");
}

// Listen value add, with type-specific filter
void OnStringValueAdd(string value) {
	Console.WriteLine($"String added: {value}");
}
Int added: 15
String added: Hello
String added: World
Current values: 4

Serialization

The Observed<T> and ObservedList<T> classes have built-in converters to the base type T and List<T> respectively. Implemented via System.Text.Json.

The serialization code is located in ObservedJsonConverter and ObservedListJsonConverter.

Tools and Extensions

...

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.13 100 7/31/2026
1.3.12 91 7/28/2026
1.3.11 94 7/23/2026
1.3.10 99 7/17/2026
1.3.9 99 7/12/2026
1.3.8 103 7/11/2026
1.3.7 96 7/11/2026
1.3.6 97 7/5/2026
1.3.5 101 7/5/2026