Some handy classes that I like to use.
Implementations of System.Text.Json.Serialization.JsonConverter<T> for the dynamic and dynamic[] types.
class MyClass {
...
[JsonInclude]
[System.Text.Json.Serialization.JsonConverter(typeof(Peeveen.Utils.Dynamic.DynamicConverter))]
public dynamic MyDynamicData { get; set; }
[JsonInclude]
[System.Text.Json.Serialization.JsonConverter(typeof(Peeveen.Utils.Dynamic.DynamicCollectionConverter))]
public dynamic[] MyDynamicDataArray { get; set; }
...
}
var result = JsonSerializer.Deserialize<MyClass>(json);
var val = result.MyDynamicData.some._dynamic.property.somewhere;Alternatively, the more direct approach ...
var serializerOptions = new JsonSerializerOptions();
serializerOptions.Converters.Add(Peeveen.Utils.Dynamic.DynamicConverter.Instance); // or new() ...
serializerOptions.Converters.Add(Peeveen.Utils.Dynamic.DynamicCollectionConverter.Instance); // or new() ...
var deserializedDynamicData = JsonSerializer.Deserialize<dynamic>(rawJsonString, serializerOptions);
var dynamicProperty = deserializedDynamicData.some._dynamic.property.somewhere;- Parameterized constructor to define behavior surrounding date detection and smaller numeric data types.
A static class with a few methods for working with dynamic data.
EvaluateExpression()allows for a string expression likex.y.z[2].blahto be evaluated against adynamicobject.GetPropertyInfo()will return an array of objects describing the top-level properties of adynamicobject.Flatten()will flatten all nested objects of adynamicinto top-level properties (optionally including arrays/lists), with property names made from a combination of parent property names using a custom separator.Merge()will merge the properties of two objects into a new object.
A wrapper around an IAsyncEnumerable to allow for it to be consumed by multiple consumers, as long
as you know how many consumers there are.
Depending on the implementation of any given IAsyncEnumerable, it may not support being enumerated
multiple times (e.g. if it is reading directly from a network stream, or a database query). So if you
want to provide the data to multiple consumers, your usual option is to first enumerate it to a
concrete collection such as a List. This could be costly in terms of memory if there is a very
large amount of data being enumerated.
This class uses a internal List buffer into which the enumerated elements are read, but:
- An item is only added to the buffer when it is requested by a consumer that has already consumed all previously-buffered items.
- Later consumers will received the buffered item(s).
- Items are removed from the buffer as soon as all consumers have consumed them.
- You can specify a maximum buffer limit to ensure that one consumer does not race ahead, filling the internal buffer with massive amounts of data and allocating large amounts of memory.
- You can specify a minimum size that the buffer must reach before the implementation will attempt a tidy-up of consumed items (to prevent unnecessary processing "churn" at the expense of slightly higher memory usage).
Extension functions for working with arrays.
ToMultidimensionalArray()will convert an array-of-arrays (of arrays, etc) to a multidimensional array. For example, it will convert anint[][][]to anint[,,].