| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- using System.Reflection;
- using System.Text.Json;
- namespace Admin.NET.Plugin.AiDOP.Rule;
- /// <summary>
- /// 规则配置纯逻辑解析器。只负责层级合并和类型转换,不访问数据库、不执行业务动作。
- /// </summary>
- public static class RuleConfigResolver
- {
- public static RuleConfigResolveResult<TOptions> Resolve<TOptions>(TOptions defaults, IEnumerable<RuleConfigLayer> layers)
- where TOptions : class, new()
- {
- var result = new RuleConfigResolveResult<TOptions> { Options = CopyOptions(defaults) };
- var properties = typeof(TOptions)
- .GetProperties(BindingFlags.Public | BindingFlags.Instance)
- .Where(x => x.CanRead && x.CanWrite)
- .ToDictionary(x => Normalize(x.Name), x => x);
- var orderedLayers = layers.OrderBy(x => x.Priority).ToList();
- foreach (var priorityGroup in orderedLayers.GroupBy(x => x.Priority))
- {
- var duplicateRules = priorityGroup
- .SelectMany(x => x.Items)
- .GroupBy(x => Normalize(x.RuleCode))
- .Where(x => x.Count() > 1)
- .Select(x => x.Key)
- .ToList();
- foreach (var duplicate in duplicateRules)
- {
- result.Errors.Add($"同一优先级存在重复规则:{duplicate}");
- }
- if (duplicateRules.Count > 0) continue;
- foreach (var layer in priorityGroup)
- {
- foreach (var item in layer.Items.Where(x => x.IsEnabled))
- {
- if (!properties.TryGetValue(Normalize(item.RuleCode), out var property))
- {
- result.Warnings.Add($"未找到规则对应属性:{item.RuleCode}");
- continue;
- }
- if (TryConvert(item, property.PropertyType, out var value, out var error))
- {
- property.SetValue(result.Options, value);
- result.AppliedItems.Add(new RuleConfigAppliedItem(layer.Scope, item.RuleCode, item.RuleValue));
- continue;
- }
- if (item.Required)
- {
- result.Errors.Add(error);
- continue;
- }
- result.Warnings.Add(error);
- if (item.IsHighRiskSwitch && property.PropertyType == typeof(bool))
- {
- property.SetValue(result.Options, false);
- result.Warnings.Add($"高风险开关配置非法,已按保守值 false 处理:{item.RuleCode}");
- }
- }
- }
- }
- return result;
- }
- private static TOptions CopyOptions<TOptions>(TOptions source)
- where TOptions : class, new()
- {
- var target = new TOptions();
- foreach (var property in typeof(TOptions).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.CanRead && x.CanWrite))
- {
- property.SetValue(target, property.GetValue(source));
- }
- return target;
- }
- private static bool TryConvert(RuleConfigItem item, Type targetType, out object? value, out string error)
- {
- var raw = item.RuleValue ?? string.Empty;
- var nullableType = Nullable.GetUnderlyingType(targetType);
- targetType = nullableType ?? targetType;
- try
- {
- if (targetType == typeof(string))
- {
- value = raw;
- error = string.Empty;
- return true;
- }
- if (targetType == typeof(bool))
- {
- if (bool.TryParse(raw, out var boolValue))
- {
- value = boolValue;
- error = string.Empty;
- return true;
- }
- }
- else if (targetType == typeof(int))
- {
- if (int.TryParse(raw, out var intValue))
- {
- value = intValue;
- error = string.Empty;
- return true;
- }
- }
- else if (targetType == typeof(long))
- {
- if (long.TryParse(raw, out var longValue))
- {
- value = longValue;
- error = string.Empty;
- return true;
- }
- }
- else if (targetType == typeof(decimal))
- {
- if (decimal.TryParse(raw, out var decimalValue))
- {
- value = decimalValue;
- error = string.Empty;
- return true;
- }
- }
- else if (targetType == typeof(List<string>))
- {
- value = JsonSerializer.Deserialize<List<string>>(raw) ?? new List<string>();
- error = string.Empty;
- return true;
- }
- else if (targetType == typeof(List<int>))
- {
- value = JsonSerializer.Deserialize<List<int>>(raw) ?? new List<int>();
- error = string.Empty;
- return true;
- }
- else if (targetType == typeof(List<decimal>))
- {
- value = JsonSerializer.Deserialize<List<decimal>>(raw) ?? new List<decimal>();
- error = string.Empty;
- return true;
- }
- else
- {
- value = JsonSerializer.Deserialize(raw, targetType);
- error = string.Empty;
- return true;
- }
- }
- catch (Exception ex)
- {
- value = null;
- error = $"规则 {item.RuleCode} 类型转换失败:{ex.Message}";
- return false;
- }
- value = null;
- error = $"规则 {item.RuleCode} 类型转换失败:值 {raw} 无法转换为 {targetType.Name}";
- return false;
- }
- private static string Normalize(string value)
- {
- return value.Replace("_", string.Empty).ToLowerInvariant();
- }
- }
- public sealed class RuleConfigLayer
- {
- public string Scope { get; set; } = string.Empty;
- public int Priority { get; set; }
- public List<RuleConfigItem> Items { get; set; } = new();
- }
- public sealed class RuleConfigItem
- {
- public string RuleCode { get; set; } = string.Empty;
- public string ValueType { get; set; } = string.Empty;
- public string? RuleValue { get; set; }
- public bool Required { get; set; }
- public bool IsEnabled { get; set; } = true;
- public bool IsHighRiskSwitch { get; set; }
- }
- public sealed class RuleConfigResolveResult<TOptions>
- {
- public TOptions Options { get; set; } = default!;
- public List<string> Warnings { get; set; } = new();
- public List<string> Errors { get; set; } = new();
- public List<RuleConfigAppliedItem> AppliedItems { get; set; } = new();
- public bool Success => Errors.Count == 0;
- }
- public sealed record RuleConfigAppliedItem(string Scope, string RuleCode, string? RuleValue);
|