Init
This commit is contained in:
88
Prefab.Base/GenericAttributes.cs
Normal file
88
Prefab.Base/GenericAttributes.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Prefab.Base;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a customizable attribute bag with change tracking for Prefab domain objects.
|
||||
/// </summary>
|
||||
public class GenericAttributes : ICanBeCustomized
|
||||
{
|
||||
private readonly Dictionary<string, object> _attributes = new();
|
||||
private readonly List<GenericAttributeChange> _changes = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
IReadOnlyDictionary<string, object> IHasGenericAttributes.GenericAttributes => new ReadOnlyDictionary<string, object>(_attributes);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ordered list of attribute mutations recorded since the last call to <see cref="ClearChanges"/>.
|
||||
/// </summary>
|
||||
public IReadOnlyList<GenericAttributeChange> Changes => _changes.AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// Provides an extension point for enforcing key/value requirements before persisting the attribute.
|
||||
/// </summary>
|
||||
/// <param name="key">The attribute key being modified.</param>
|
||||
/// <param name="value">The proposed attribute value.</param>
|
||||
protected virtual void ValidateAttribute(string key, object value)
|
||||
{
|
||||
// Default: no validation. Override in derived classes for custom logic.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets or replaces an attribute value and records the mutation.
|
||||
/// </summary>
|
||||
/// <param name="key">The attribute key to set.</param>
|
||||
/// <param name="value">The attribute value.</param>
|
||||
public void SetAttribute(string key, object value)
|
||||
{
|
||||
_attributes.TryGetValue(key, out var oldValue);
|
||||
ValidateAttribute(key, value);
|
||||
_attributes[key] = value;
|
||||
_changes.Add(new GenericAttributeChange(key, oldValue, value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an attribute if present and records the removal.
|
||||
/// </summary>
|
||||
/// <param name="key">The attribute key to remove.</param>
|
||||
/// <returns><c>true</c> when the key existed and was removed; otherwise <c>false</c>.</returns>
|
||||
public bool RemoveAttribute(string key)
|
||||
{
|
||||
if (_attributes.TryGetValue(key, out var oldValue) && _attributes.Remove(key))
|
||||
{
|
||||
_changes.Add(new GenericAttributeChange(key, oldValue, null));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to read an attribute value and cast it to the requested type.
|
||||
/// </summary>
|
||||
/// <param name="key">The attribute key to read.</param>
|
||||
/// <param name="value">Receives the typed attribute value when successful.</param>
|
||||
/// <typeparam name="T">The expected attribute type.</typeparam>
|
||||
/// <returns><c>true</c> when the attribute exists and matches the requested type.</returns>
|
||||
public bool TryGetAttribute<T>(string key, out T value)
|
||||
{
|
||||
if (_attributes.TryGetValue(key, out var obj) && obj is T t)
|
||||
{
|
||||
value = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = default!;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an immutable snapshot copy of the current attributes.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, object> Snapshot() => new ReadOnlyDictionary<string, object>(new Dictionary<string, object>(_attributes));
|
||||
|
||||
/// <summary>
|
||||
/// Clears all recorded attribute changes while keeping the current attribute values intact.
|
||||
/// </summary>
|
||||
public void ClearChanges() => _changes.Clear();
|
||||
}
|
||||
Reference in New Issue
Block a user