![]() |
VOOZH | about |
dotnet add package HashTableRx --version 2.3.2
NuGet\Install-Package HashTableRx -Version 2.3.2
<PackageReference Include="HashTableRx" Version="2.3.2" />
<PackageVersion Include="HashTableRx" Version="2.3.2" />Directory.Packages.props
<PackageReference Include="HashTableRx" />Project file
paket add HashTableRx --version 2.3.2
#r "nuget: HashTableRx, 2.3.2"
#:package HashTableRx@2.3.2
#addin nuget:?package=HashTableRx&version=2.3.2Install as a Cake Addin
#tool nuget:?package=HashTableRx&version=2.3.2Install as a Cake Tool
A reactive hash table that mirrors the structure of an object into a dotted path key/value store you can observe and update.
HashTableRx lets you:
dotnet add package HashTableRxUseUpperCase is true, all keys are normalized to uppercase for reads/writes/observations.Value<T>(path). Writing with Value(path, value) requires the variable to already exist; otherwise InvalidVariableException is thrown (to prevent silent writes).using CP.Collections;
using System.Reactive.Linq;
// Create a reactive hash table (case sensitive keys)
var h = new HashTableRx(useUpperCase: false);
// Create a few variables using the string indexer
h["System.Online"] = true; // bool
h["Process.Temperature.CV"] = 20f; // float
// Read variables
bool online = h.Value<bool>("System.Online") ?? false;
float temp = h.Value<float>("Process.Temperature.CV") ?? 0f;
// Observe changes to an individual variable
var sub1 = h.Observe<float>("Process.Temperature.CV")
.Subscribe(v => Console.WriteLine($"Temp changed to {v}"));
// Update a value (variable must already exist for Value(..) write)
h.Value("Process.Temperature.CV", 25f);
// Or use the indexer to create and/or set directly (creates if missing)
h["Process.Temperature.SP"] = 30f;
// Observe all changes
var sub2 = h.ObserveAll
.Subscribe(kv => Console.WriteLine($"{kv.key} => {kv.value}"));
// Cleanup
sub1.Dispose();
sub2.Dispose();
var h = new HashTableRx(useUpperCase: true);
// All keys are normalized to uppercase internally
h["Rig.Temp.PV"] = 10f;
Console.WriteLine(h.Value<float>("rig.temp.pv")); // 10
Console.WriteLine(h.Value<float>("RIG.TEMP.PV")); // 10
// Observations also normalize
using var sub = h.Observe<float>("rig.temp.pv").Subscribe(v => Console.WriteLine(v));
h.Value("RIG.TEMP.PV", 11f); // Emits 11
You can reflect any object instance (e.g., created via reflection from an external assembly) into the hash table.
using System.Reflection;
using CP.Collections;
// Load an external assembly and create an instance
var asm = Assembly.LoadFrom(@"path\to\UnknownLibrary.dll");
var obj = asm.CreateInstance("Namespace.TypeName");
var h = new HashTableRx(useUpperCase: false);
// Populate the hash table from the object's public fields/properties
h.SetStructure(obj!);
// Now you can read values from reflected primitive-like fields/properties
var pv = h.Value<float>("Some.Structured.Path.PV");
// Update values in the hash table
h.Value("Some.Structured.Path.SP", 42.0f);
// Push current hash table values back to the original object
var updated = h.GetStructure();
// 'updated' is the same instance with primitive-like values written back
Notes:
String indexer h["A.B.C"]:
Value API:
T? Value<T>(string path): typed read, returns default when missing.bool Value<T>(string path, T value): typed write. Throws InvalidVariableException if the variable does not exist.Example:
var h = new HashTableRx(false);
// Create then write
h["A.B.C"] = 1;
h.Value("A.B.C", 2); // ok
// Attempting to write unknown path throws
Assert.Throws<InvalidVariableException>(() => h.Value("X.Y.Z", 5));
Observe<T>(path): emits typed values on change (distinct until changed).ObserveAll: emits (key, object?) for any change (also distinct until changed at the tuple level).var h = new HashTableRx(false);
// Create initial variable then observe
h["A.B.C"] = 10;
using var sub = h.Observe<int>("A.B.C").Subscribe(v => Console.WriteLine($"A.B.C = {v}"));
h.Value("A.B.C", 10); // may not emit due to DistinctUntilChanged
h.Value("A.B.C", 11); // emits 11
using var subAll = h.ObserveAll.Subscribe(kv => Console.WriteLine($"{kv.key} => {kv.value}"));
h["X.Y"] = 3.14f; // emits ("X.Y", 3.14f)
var h = new HashTableRx(false);
// Writes automatically create intermediate nodes
h["Plant.Unit1.Pump.Speed"] = 1200;
// Reads follow the same structure
int? speed = h.Value<int>("Plant.Unit1.Pump.Speed");
// Switching a scalar to a branch via write
h["Plant.Unit1"] = 123; // was scalar
h["Plant.Unit1.Pump.Speed"] = 900; // Node becomes a nested table to accommodate deeper path
The bool indexer h[true] is a convenience to reflect the entire object graph to and from the hash table.
var h = new HashTableRx(false);
// Push an object's values into the table
h[true] = myObject; // equivalent to h.SetStructure(myObject)
// Later, materialize current values back into the object
var updated = h[true]; // equivalent to h.GetStructure()
HashTableRx derives from a reactive HashTable that is observable as a sequence of (key, value) updates.
Add(object key, object? value): Adds a key/value (also notifies observers).Remove(object key): Removes a key (scheduled).Clear(): Clears all entries (scheduled).Get(object key): Returns IObservable<(string key, object value)> that reads the indexer on a scheduler.var ht = new HashTable();
ht.Add("K", 123);
var (k, v) = ht.Get("K").Wait(); // ("K", 123)
ht.Remove("K");
ht.Clear();
InvalidVariableException: thrown by Value(path, value) when the variable does not exist.InvalidCastException: thrown by Value(path, value) when the existing variable type is incompatible with value.try
{
h.Value("A.B.C", "wrong-type");
}
catch (InvalidCastException ex)
{
Console.WriteLine(ex.Message);
}
SetStructure/GetStructure is optimized using compiled expression trees and caching per Type.PropertyInfo/FieldInfo.GetValue/SetValue loops.SetStructure) and then use Value(path, value) for updates.HashTableRx with useUpperCase: true.Value<T>(path) for typed reads. It returns default(T) when missing instead of throwing.h["A.B.C"] = value) or SetStructure first. Value(path, value) enforces that the variable already exists.MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. 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. 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. 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. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net461 net461 was computed. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 1 NuGet packages that depend on HashTableRx:
| Package | Downloads |
|---|---|
|
CP.TwinCATRx
A Reactive TwinCAT PLC Library |
This package is not used by any popular GitHub repositories.
Compatability with Net 8 / 9 / 10 and netstandard2.0