Files
SteamTools/System.Common.CoreLib/Application/Services/Implementation/ModelValidator.cs
T
2021-02-20 16:45:44 +08:00

86 lines
2.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
namespace System.Application.Services.Implementation
{
/// <inheritdoc cref="IModelValidator"/>
public class ModelValidator : IModelValidator
{
static readonly MethodInfo matchValidateMethod = typeof(ModelValidator).GetMethod(nameof(MatchValidate), BindingFlags.NonPublic | BindingFlags.Static);
static readonly IDictionary<Type, object> validators = new Dictionary<Type, object>();
public static void AddColumnValidate<T>(Func<T, string?> 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<T>(
Func<T, string?> validate,
object model,
bool hasIgnores,
Type[] ignores,
Func<string[]> 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<string[]> 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;
}
}
}