using System.Linq.Expressions; namespace AIStudio.Settings; public sealed class SettingsLocker { private static readonly ILogger LOGGER = Program.LOGGER_FACTORY.CreateLogger(); private readonly Dictionary> lockedProperties = new(); public void Register(Expression> propertyExpression, Guid configurationPluginId) { var memberExpression = GetMemberExpression(propertyExpression); var className = typeof(T).Name; var propertyName = memberExpression.Member.Name; if (!this.lockedProperties.ContainsKey(className)) this.lockedProperties[className] = []; this.lockedProperties[className].TryAdd(propertyName, configurationPluginId); } public void Remove(Expression> propertyExpression) { var memberExpression = GetMemberExpression(propertyExpression); var className = typeof(T).Name; var propertyName = memberExpression.Member.Name; if (this.lockedProperties.TryGetValue(className, out var props)) { if (props.Remove(propertyName)) { // If the property was removed, check if the class has no more locked properties: if (props.Count == 0) this.lockedProperties.Remove(className); } } } public Guid GetConfigurationPluginId(Expression> propertyExpression) { var memberExpression = GetMemberExpression(propertyExpression); var className = typeof(T).Name; var propertyName = memberExpression.Member.Name; if (this.lockedProperties.TryGetValue(className, out var props) && props.TryGetValue(propertyName, out var configurationPluginId)) return configurationPluginId; // No configuration plugin ID found for this property: return Guid.Empty; } public bool IsLocked(Expression> propertyExpression) { var memberExpression = GetMemberExpression(propertyExpression); var className = typeof(T).Name; var propertyName = memberExpression.Member.Name; return this.lockedProperties.TryGetValue(className, out var props) && props.ContainsKey(propertyName); } private static MemberExpression GetMemberExpression(Expression> expression) { switch (expression.Body) { // Case for value types, which are wrapped in UnaryExpression: case UnaryExpression { NodeType: ExpressionType.Convert } unaryExpression: return (MemberExpression)unaryExpression.Operand; // Case for reference types, which are directly MemberExpressions: case MemberExpression memberExpression: return memberExpression; default: LOGGER.LogError($"Expression '{expression}' is not a valid property expression."); throw new ArgumentException($"Expression '{expression}' is not a valid property expression.", nameof(expression)); } } }