Class State
State class represents the state maintained by the user of a system to make sense of the behavior of the system. It is not the internal state of the system though it is probably similar to the internal state of the system.
This is an abstract class and defines properties and methods that should be implemented by all state objects.
public abstract class State : IState
- Inheritance
-
State
- Implements
- Inherited Members
Fields
stateHash
protected ulong? stateHash
Field Value
stringRepresentation
protected string stringRepresentation
Field Value
Properties
EnableFreezeValidation
Controls whether ValidateNotMutated() performs validation. Set to false to disable validation for performance in production scenarios. Default is true.
public static bool EnableFreezeValidation { get; set; }
Property Value
IsFrozen
Indicates whether a state object is frozen (immutable). State objects are not frozen when initially created so the user can modify the state in an 'imperative' fashion. They are then frozen by the framework once returned from the method that created them so they are effectively immutable. Once frozen, the only way to modify a state object is to clone it to create a new state object that can be modified till it's also eventually frozen.
[JsonIgnore]
public bool IsFrozen { get; protected set; }
Property Value
Random
public static Random Random { get; }
Property Value
Methods
AppendFieldHashes(XxHash64, Dictionary<object, int>)
Appends hash data for this state's fields to the hasher. Override in derived classes for efficient incremental hashing. The cycle check is handled by AppendHashCore(XxHash64, Dictionary<object, int>) - this method only needs to append field data.
protected virtual void AppendFieldHashes(XxHash64 hasher, Dictionary<object, int> visited)
Parameters
hasherXxHash64The XxHash64 hasher to append data to.
visitedDictionary<object, int>Dictionary of already-visited objects, passed to nested states.
AppendHashCore(XxHash64, Dictionary<object, int>)
Appends this state's hash data to the provided hasher. This method handles cycle detection and delegates to the generated override. Nested states call this method to append directly to the parent's hasher, avoiding early collapse to 64 bits.
public void AppendHashCore(XxHash64 hasher, Dictionary<object, int> visited)
Parameters
hasherXxHash64The XxHash64 hasher to append data to.
visitedDictionary<object, int>Dictionary mapping visited objects to their reference IDs for back-reference handling.
AppendLengthPrefixedString(XxHash64, string)
Appends a length-prefixed string to the hasher. The length (in bytes) is prepended to prevent boundary collisions (e.g., "ab" + "c" vs "a" + "bc").
public static void AppendLengthPrefixedString(XxHash64 hasher, string value)
Parameters
Clone()
Clones the state object. The cloned state object is initially not frozen.
public virtual State Clone()
Returns
Clone(Dictionary<object, object>)
Clones the state object. This method is supposed to be called by other State objects internally and should not be directly called by users.
public State Clone(Dictionary<object, object> clonedMap)
Parameters
clonedMapDictionary<object, object>
Returns
CloneInternal(Dictionary<object, object>)
This method should clone the state set the cloned state in the map. It does not need to check whether the clone is already present in clonedMap or not as it is only called if there is not an entry in clonedMap. It should however set the clone in the map, before calling the Clone method on its sub-components (as they may recursively point back to the parent).
protected abstract void CloneInternal(Dictionary<object, object> clonedMap)
Parameters
clonedMapDictionary<object, object>
CloneWithMap()
Clones the state object. The cloned state object is initially not frozen. This also returns a map that maps objects in the original state to corresponding objects in the cloned state.
public (State, Dictionary<object, object>) CloneWithMap()
Returns
- (State, Dictionary<object, object>)
CloneWithMap<TState>()
public (TState, Dictionary<object, object>) CloneWithMap<TState>() where TState : State
Returns
- (TState, Dictionary<object, object>)
Type Parameters
TState
ComputeHash64(string)
Computes a 64-bit hash of the given string using XxHash64.
public static ulong ComputeHash64(string str)
Parameters
strstring
Returns
Freeze()
Freezes the state, making it immutable. Any attempts to modify a frozen state object should result in the StateFrozenException exception being thrown.
public void Freeze()
Freeze(HashSet<object>)
public void Freeze(HashSet<object> visited)
Parameters
FreezeComponents(HashSet<object>)
Derived state objects must recursively call FreezeComponents(HashSet<object>) on state objects they are composed of.
protected abstract void FreezeComponents(HashSet<object> visited)
Parameters
GetStableTypeName(Type)
Gets a stable type name that doesn't include assembly-qualified generic type arguments.
For non-generic types, returns the same as Type.FullName.
For closed generics (e.g., Container<ItemState>), Type.FullName includes assembly
version info in the generic arguments, making fingerprints/hashes version-dependent.
This method strips that info, producing a name like:
"Ns.Container1[Ns.ItemState]" instead of "Ns.Container1[[Ns.ItemState, Assembly, Version=...]]"
public static string GetStableTypeName(Type type)
Parameters
typeType
Returns
GetStateHash()
Returns the 64-bit state hash, computed incrementally using XxHash64. Cached for frozen states.
public ulong GetStateHash()
Returns
LockComponents(HashSet<object>)
Obsolete. Override FreezeComponents(HashSet<object>) instead.
[Obsolete("Override FreezeComponents instead")]
protected virtual void LockComponents(HashSet<object> visited)
Parameters
StringRepresentation()
Returns a string representation of the state. The string representation of the state is not just a human-friendly text representation but also serves as the value over which the state hash is computed. Care must be taken to ensure that two different state objects must have different string representations; they will map to the same state hash if they are not different.
public string StringRepresentation()
Returns
StringRepresentation(bool)
Returns the string representation, optionally bypassing the cache.
public string StringRepresentation(bool forceRecompute)
Parameters
forceRecomputeboolIf true, recomputes even for frozen objects (propagates to nested states).
Returns
StringRepresentation(Dictionary<object, string>, string)
See StringRepresentation() for details. This method should not be directly called by users and only by other classes that inherit from the State class.
public string StringRepresentation(Dictionary<object, string> objectPaths, string path)
Parameters
objectPathsDictionary<object, string>pathstring
Returns
StringRepresentation(Dictionary<object, string>, string, bool)
Internal overload with forceRecompute parameter.
public string StringRepresentation(Dictionary<object, string> objectPaths, string path, bool forceRecompute)
Parameters
objectPathsDictionary<object, string>pathstringforceRecomputebool
Returns
StringRepresentationInternal(Dictionary<object, string>, string, bool)
Derived classes must implement this method to return a unique string representation of the state they represent. The derived class should call the StringRepresentation(Dictionary<object, string>, string, bool) method when fetching the string representation of sub-components. They must pass the objectPaths, path, and forceRecompute parameters to the nested calls.
protected abstract string StringRepresentationInternal(Dictionary<object, string> objectPaths, string path, bool forceRecompute)
Parameters
objectPathsDictionary<object, string>pathstringforceRecomputebool
Returns
ToString()
public override string ToString()
Returns
ValidateNotMutated()
Validates that a frozen state has not been mutated since it was frozen. Throws StateFrozenException if mutation is detected. This check can be disabled by setting EnableFreezeValidation to false.
public void ValidateNotMutated()
Exceptions
- StateFrozenException
Thrown if the state was mutated after freezing.