using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; namespace System.Application.Services.Implementation { /// public class ModelValidator : IModelValidator { static readonly MethodInfo matchValidateMethod = typeof(ModelValidator).GetMethod(nameof(MatchValidate), BindingFlags.NonPublic | BindingFlags.Static); static readonly IDictionary validators = new Dictionary(); public static void AddColumnValidate(Func validate) => validators.Add(typeof(T), validate); const string I = "I"; const string IReadOnly = "IReadOnly"; const string IReadOnlyNullable = "IReadOnlyNullable"; static readonly string[] StartsWithSubstrings = new[] { IReadOnlyNullable, IReadOnly, I }; static string GetColumnName(Type type) { foreach (var item in StartsWithSubstrings) { if (type.Name.StartsWith(item)) { return type.Name[item.Length..]; } } return type.Name; } static string? MatchValidate( Func validate, object model, bool hasIgnores, Type[] ignores, Func ignoreNames) { if (hasIgnores) { var type = typeof(T); if (ignores.Contains(type) || ignoreNames().Contains(GetColumnName(type))) { return null; } } if (model is T t) { return validate(t); } return null; } public bool Validate(object model, [NotNullWhen(false)] out string? errorMessage, params Type[] ignores) { string[]? ignoreNames_ = null; Func ignoreNames = GetIgnoreNames; string[] GetIgnoreNames() { if (ignoreNames_ == null) { ignoreNames_ = ignores.Select(GetColumnName).ToArray(); } return ignoreNames_; } var hasIgnores = ignores.Any_Nullable(); if (!validators.Any()) { // 验证组不能为空集合! throw new NotSupportedException("validators cannot be empty."); } foreach (var item in validators) { var parameters = new object?[] { item.Value, model, hasIgnores, ignores, ignoreNames }; errorMessage = (string)matchValidateMethod.MakeGenericMethod(item.Key).Invoke(null, parameters); if (errorMessage != null) return false; } errorMessage = null; return true; } } }