Files
zszq-trs/YLErpDAL/Modules/SuperviseReportModule/SAC/Common/BaseCheckHelper.cs
T

1217 lines
40 KiB
C#

using System.Globalization;
using System.Reflection;
namespace YLErp.Modules.SuperviseReportModule.SAC.Common
{
#region CheckAttrbute
/// <summary>
/// 检查字段属性基类
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
public abstract class BaseCheckAttribute : Attribute
{
/// <summary>
/// 是否必填
/// <para>默认为true</para>
/// </summary>
public bool Required { get; set; } = true;
/// <summary>
/// 处理逻辑名称
/// <para>该值主要为<see cref="BaseCheckConditionAttribute"/>的派生类提供指定处理逻辑时的绑定名称,如果不需要指定,则该字段不应填写</para>
/// <para>该值不为Null时,则应在<see cref="BaseCheckConditionAttribute"/>的派生类中<see cref="BaseCheckConditionAttribute.CheckHandleNameArr"/>字段中指定,否则永远不会被执行</para>
/// </summary>
public string CheckHandleName { get; set; }
/// <summary>
/// 是否需要修改值
/// </summary>
public bool UseChangeValue { get; protected set; }
/// <summary>
/// 修改后的值
/// </summary>
public object ChangedValue { get; protected set; }
/// <summary>
/// 错误提示
/// </summary>
public abstract string ErrMsg { get; set; }
public abstract bool Execute(object value);
}
/// <summary>
/// 检查字符串字段属性基类
/// </summary>
public abstract class BaseCheckStringAttribute : BaseCheckAttribute
{
/// <summary>
/// Null或空白字符是否通过检查
/// <para>仅Required=true时有效</para>
/// <para>默认为和Required一致</para>
/// </summary>
public bool IgnoreNullOrEmpty { get; set; } = false;
public override bool Execute(object value)
{
var state = false;
var text = (value?.ToString()) ?? "";
if (text.Length == 0)
{
state = !Required || IgnoreNullOrEmpty;
}
else
{
state = Execute(value?.ToString());
}
if (!state)
{
ErrMsg = GenerateErrMsg(value?.ToString());
}
return state;
}
protected abstract string GenerateErrMsg(string value);
protected abstract bool Execute(string value);
}
/// <summary>
/// 检查字符串长度
/// <para>字符串长度是否等于预设值</para>
/// </summary>
public sealed class CheckStringLengthAttribute : BaseCheckStringAttribute
{
/// <summary>
/// 字符串长度
/// </summary>
public int Length { get; set; }
private string _errMsg;
/// <summary>
/// 错误提示
/// <para>默认为:{fieldName}={fieldValue}不合法,长度应为{Length}</para>
/// </summary>
public override string ErrMsg
{
get
{
if (string.IsNullOrWhiteSpace(_errMsg))
{
//_errMsg = "{fieldName}={fieldValue}不合法,值不应为空,且长度应为{Length}";
_errMsg = "值不应为空,且长度应为{Length}";
}
return _errMsg;
}
set
{
_errMsg = value;
}
}
protected override bool Execute(string value)
{
return (value ?? "").Length == Length;
}
protected override string GenerateErrMsg(string value)
{
return ErrMsg.Replace("{fieldValue}", value).Replace("{Length}", Length.ToString());
}
}
/// <summary>
/// 检查字符串最大长度
/// <para>字符串长度是否超过预设值</para>
/// </summary>
public sealed class CheckStringMaxLengthAttribute : BaseCheckStringAttribute
{
/// <summary>
/// 字符串最大长度
/// </summary>
public int MaxLength { get; set; }
private string _errMsg;
/// <summary>
/// 错误提示
/// <para>默认为:{fieldName}={fieldValue}不合法,最大长度不应超过{MaxLength}</para>
/// </summary>
public override string ErrMsg
{
get
{
if (string.IsNullOrWhiteSpace(_errMsg))
{
//_errMsg = "{fieldName}={fieldValue}不合法,值不应为空,且最大长度不应超过{MaxLength}";
_errMsg = "值不应为空,且最大长度不应超过{MaxLength}";
}
return _errMsg;
}
set
{
_errMsg = value;
}
}
protected override bool Execute(string value)
{
return (value ?? "").Length <= MaxLength;
}
protected override string GenerateErrMsg(string value)
{
return ErrMsg.Replace("{fieldValue}", value).Replace("{MaxLength}", MaxLength.ToString());
}
}
/// <summary>
/// 检查字符串最小长度
/// <para>字符串长度是否低于预设值</para>
/// </summary>
public sealed class CheckStringMinLengthAttribute : BaseCheckStringAttribute
{
/// <summary>
/// 字符串最小长度
/// </summary>
public int MinLength { get; set; }
private string _errMsg;
/// <summary>
/// 错误提示
/// <para>默认为:{fieldName}={fieldValue}不合法,长度不应小于{MinLength}</para>
/// </summary>
public override string ErrMsg
{
get
{
if (string.IsNullOrWhiteSpace(_errMsg))
{
//_errMsg = "{fieldName}={fieldValue}不合法,值不应为空,且长度不应小于{MinLength}";
_errMsg = "值不应为空,且长度不应小于{MinLength}";
}
return _errMsg;
}
set
{
_errMsg = value;
}
}
protected override bool Execute(string value)
{
return (value ?? "").Length >= MinLength;
}
protected override string GenerateErrMsg(string value)
{
return ErrMsg.Replace("{fieldValue}", value).Replace("{MinLength}", MinLength.ToString());
}
}
/// <summary>
/// 检查字符串结尾
/// <para>检查字符串是否以预设值结尾</para>
/// </summary>
public sealed class CheckStringEndsWithAttribute : BaseCheckStringAttribute
{
/// <summary>
/// 指定字符串结尾部分
/// </summary>
public string EndsWithString { get; set; }
/// <summary>
/// 多选模式
/// <para>该字段为true时,将使用<see cref="SplitStr"/>对<see cref="EndsWithString"/>分割后,进行匹配</para>
/// </summary>
public bool Multiple { get; set; }
/// <summary>
/// 多条件分隔符
/// </summary>
public string SplitStr { get; set; } = "|";
/// <summary>
/// 如字符串为英文字母,是否忽略大小写
/// <para>默认为:true</para>
/// </summary>
public bool IgnoreCase { get; set; } = true;
private string _errMsg;
/// <summary>
/// 错误提示
/// <para>默认为:{fieldName}={fieldValue}不合法,内容应以{EndsWithString}结尾</para>
/// </summary>
public override string ErrMsg
{
get
{
if (string.IsNullOrWhiteSpace(_errMsg))
{
//_errMsg = "{fieldName}={fieldValue}不合法,值不应为空,且内容应以{EndsWithString}结尾";
_errMsg = "值不应为空,且内容应以{EndsWithString}结尾";
}
return _errMsg;
}
set
{
_errMsg = value;
}
}
protected override bool Execute(string value)
{
var match = false;
if (Multiple)
{
var split = EndsWithString.Split(SplitStr.ToCharArray());
foreach (var item in split)
{
match = (value ?? "").EndsWith(item, IgnoreCase, CultureInfo.CurrentCulture);
if (match) { break; }
}
}
else
{
match = (value ?? "").EndsWith(EndsWithString, IgnoreCase, CultureInfo.CurrentCulture);
}
return match;
}
protected override string GenerateErrMsg(string value)
{
return ErrMsg.Replace("{fieldValue}", value).Replace("{EndsWithString}", EndsWithString);
}
}
/// <summary>
/// 检查字符串是否为指定格式的DateTime字符串
/// </summary>
public sealed class CheckStringIsDateTimeFormatAttribute : BaseCheckStringAttribute
{
/// <summary>
/// DateTime类型支持的格式化字符
/// <para>默认为:yyyy-MM-dd</para>
/// </summary>
public string FormatString { get; set; } = "yyyy-MM-dd";
private string _errMsg;
/// <summary>
/// 错误提示
/// <para>默认为:{fieldName}={fieldValue}不合法,不匹配{FormatString}格式</para>
/// </summary>
public override string ErrMsg
{
get
{
if (string.IsNullOrWhiteSpace(_errMsg))
{
//_errMsg = "{fieldName}={fieldValue}不合法,不匹配{FormatString}格式";
_errMsg = "不匹配{FormatString}格式";
}
return _errMsg;
}
set
{
_errMsg = value;
}
}
protected override bool Execute(string value)
{
var result = true;
try
{
result = DateTime.TryParseExact(value ?? "", FormatString, CultureInfo.CurrentCulture, DateTimeStyles.None, out _);
if (!result)
{
result = DateTime.TryParse(value ?? "", out var temp);
if (result)
{
UseChangeValue = true;
ChangedValue = temp.ToString(FormatString);
}
}
}
catch
{
result = false;
}
return result;
}
protected override string GenerateErrMsg(string value)
{
return ErrMsg.Replace("{fieldValue}", value).Replace("{FormatString}", FormatString);
}
}
/// <summary>
/// 检查字符串是否为数字或百分数,长度在指定范围内,可选是否检查值的合法区间
/// </summary>
public sealed class CheckStringIntOrPercentRangeAttribute : BaseCheckStringAttribute
{
/// <summary>
/// 值为数字时小数点前最大长度
/// </summary>
public int BeforePointMaxLength_Number { get; set; }
/// <summary>
/// 值为数字时小数点后最大长度
/// </summary>
public int AfterPointMaxLength_Number { get; set; }
/// <summary>
/// 值为数字时最大值
/// <para>可选,不设置则不检查</para>
/// </summary>
public double MaxValue_Number { get; set; } = double.NaN;
/// <summary>
/// 值为数字时最小值
/// <para>可选,不设置则不检查</para>
/// </summary>
public double MinValue_Number { get; set; } = double.NaN;
/// <summary>
/// 值为百分数时小数点前最大长度
/// </summary>
public int BeforePointMaxLength_Percent { get; set; }
/// <summary>
/// 值为百分数时小数点后最大长度
/// </summary>
public int AfterPointMaxLength_Percent { get; set; }
/// <summary>
/// 值为百分数时最大值
/// <para>可选,不设置则不检查</para>
/// </summary>
public double MaxValue_Percent { get; set; } = double.NaN;
/// <summary>
/// 值为百分数时最小值
/// <para>可选,不设置则不检查</para>
/// </summary>
public double MinValue_Percent { get; set; } = double.NaN;
private string _errMsg;
/// <summary>
/// 错误提示
/// <para>默认为:</para>
/// <para>{fieldName}={fieldValue}不合法,保留位数为[{BeforePointMaxLength},{AfterPointMaxLength}],取值区间为[&gt;{MinValue},&lt;{MaxValue}]</para>
/// </summary>
public override string ErrMsg
{
get
{
if (string.IsNullOrWhiteSpace(_errMsg))
{
//_errMsg = "{fieldName}={fieldValue}不合法,值应为数字,且保留位数为[{BeforePointMaxLength},{AfterPointMaxLength}]";
_errMsg = "值应为数字,且保留位数为[{BeforePointMaxLength},{AfterPointMaxLength}]";
double minValue, maxValue;
if (isPercent)
{
minValue = MinValue_Percent;
maxValue = MaxValue_Percent;
}
else
{
minValue = MinValue_Number;
maxValue = MaxValue_Number;
}
var msgArr = new List<string>();
if (!double.IsNaN(minValue))
{
msgArr.Add(">={MinValue}");
}
if (!double.IsNaN(maxValue))
{
msgArr.Add("<={MaxValue}");
}
if (msgArr.Count > 0)
{
_errMsg += $",取值范围为[{string.Join(",", msgArr)}]";
}
}
return _errMsg;
}
set
{
_errMsg = value;
}
}
private bool isPercent;
protected override bool Execute(string value)
{
int beforePointMaxLength, afterPointMaxLength;
double maxValue, minValue;
isPercent = isPercent = value != null && value.EndsWith("%");
if (isPercent)
{
value = value.Remove(value.Length - 1);
beforePointMaxLength = BeforePointMaxLength_Percent;
afterPointMaxLength = AfterPointMaxLength_Percent;
maxValue = MaxValue_Percent;
minValue = MinValue_Percent;
}
else
{
beforePointMaxLength = BeforePointMaxLength_Number;
afterPointMaxLength = AfterPointMaxLength_Number;
maxValue = MaxValue_Number;
minValue = MinValue_Number;
}
if (!double.TryParse(value, out var temp))
{
return false;
}
var part = (value ?? "").Split('.');
if (part.Length > 2)
{
return false;
}
if (part[0].Length > beforePointMaxLength)
{
return false;
}
if (!double.IsNaN(maxValue) && temp > maxValue)
{
return false;
}
if (!double.IsNaN(minValue) && temp < minValue)
{
return false;
}
if (part.Length > 1 && part[1].Length > afterPointMaxLength)
{
UseChangeValue = true;
string sufix = "0.".PadRight(afterPointMaxLength + 2, '0');
UseChangeValue = true;
ChangedValue = temp.ToString(sufix) + (isPercent ? "%" : "");
return true;
}
return true;
}
protected override string GenerateErrMsg(string value)
{
int beforePointMaxLength, afterPointMaxLength;
double maxValue, minValue;
isPercent = isPercent = value != null && value.EndsWith("%");
if (isPercent)
{
value = value.Remove(value.Length - 2);
beforePointMaxLength = BeforePointMaxLength_Percent;
afterPointMaxLength = AfterPointMaxLength_Percent;
maxValue = MaxValue_Percent;
minValue = MinValue_Percent;
}
else
{
beforePointMaxLength = BeforePointMaxLength_Number;
afterPointMaxLength = AfterPointMaxLength_Number;
maxValue = MaxValue_Number;
minValue = MinValue_Number;
}
return ErrMsg
.Replace("{fieldValue}", value)
.Replace("{BeforePointMaxLength}", beforePointMaxLength.ToString())
.Replace("{AfterPointMaxLength}", afterPointMaxLength.ToString())
.Replace("{MinValue}", minValue.ToString())
.Replace("{MaxValue}", maxValue.ToString());
}
}
/// <summary>
/// 检查字符串是否为数字,长度在指定范围内,可选是否检查值的合法区间
/// </summary>
public sealed class CheckStringIntMaxLengthAttribute : BaseCheckStringAttribute
{
/// <summary>
/// 小数点前最大长度
/// </summary>
public int BeforePointMaxLength { get; set; }
/// <summary>
/// 小数点后最大长度
/// </summary>
public int AfterPointMaxLength { get; set; }
/// <summary>
/// 最大值
/// <para>可选,不设置则不检查</para>
/// </summary>
public double MaxValue { get; set; } = double.NaN;
/// <summary>
/// 最小值
/// <para>可选,不设置则不检查</para>
/// </summary>
public double MinValue { get; set; } = double.NaN;
private string _errMsg;
/// <summary>
/// 错误提示
/// <para>默认为:{fieldName}={fieldValue}不合法,最大保留位数为[{BeforePointMaxLength},{AfterPointMaxLength}],取值范围为[&gt;{MinValue},&lt;{MaxValue}]</para>
/// </summary>
public override string ErrMsg
{
get
{
if (string.IsNullOrWhiteSpace(_errMsg))
{
//_errMsg = "{fieldName}={fieldValue}不合法,值应为数字,且最大保留位数为[{BeforePointMaxLength},{AfterPointMaxLength}]";
_errMsg = "值应为数字,且最大保留位数为[{BeforePointMaxLength},{AfterPointMaxLength}]";
var msgArr = new List<string>();
if (!double.IsNaN(MinValue))
{
msgArr.Add(">={MinValue}");
}
if (!double.IsNaN(MaxValue))
{
msgArr.Add("<={MaxValue}");
}
if (msgArr.Count > 0)
{
_errMsg += $",取值范围为[{string.Join(",", msgArr)}]";
}
}
return _errMsg;
}
set
{
_errMsg = value;
}
}
protected override bool Execute(string value)
{
if (!double.TryParse(value, out var temp))
{
return false;
}
var part = (value ?? "").Split('.');
if (part.Length > 2)
{
return false;
}
if (part[0].Length > BeforePointMaxLength)
{
return false;
}
var state = true;
if (part.Length == 1 || (part.Length > 1 && part[1].Length != AfterPointMaxLength))
{
UseChangeValue = true;
var sufix = "0.".PadRight(AfterPointMaxLength + 2, '0');
UseChangeValue = true;
ChangedValue = temp.ToString(sufix);
state = true;
}
if (!double.IsNaN(MinValue) && temp < MinValue)
{
state = false;
}
if (!double.IsNaN(MaxValue) && temp > MaxValue)
{
state = false;
}
return state;
}
protected override string GenerateErrMsg(string value)
{
return ErrMsg
.Replace("{fieldValue}", value)
.Replace("{BeforePointMaxLength}", BeforePointMaxLength.ToString())
.Replace("{AfterPointMaxLength}", AfterPointMaxLength.ToString())
.Replace("{MinValue}", MinValue.ToString())
.Replace("{MaxValue}", MaxValue.ToString());
}
}
/// <summary>
/// 检查字符串是否为数字,长度在指定范围内(小数长度必须和预设值相等),可选是否检查值的合法区间
/// </summary>
public sealed class CheckStringIntLengthAttribute : BaseCheckStringAttribute
{
/// <summary>
/// 小数点前最大长度
/// </summary>
public int BeforePointMaxLength { get; set; }
/// <summary>
/// 小数点后长度
/// <para>小数位必须与该值相等,否则应使用<see cref="CheckStringIntMaxLengthAttribute"/></para>
/// </summary>
public int AfterPointLength { get; set; }
/// <summary>
/// 最大值
/// <para>可选,不设置则不检查</para>
/// </summary>
public double MaxValue { get; set; } = double.NaN;
/// <summary>
/// 最小值
/// <para>可选,不设置则不检查</para>
/// </summary>
public double MinValue { get; set; } = double.NaN;
private string _errMsg;
/// <summary>
/// 错误提示
/// <para>默认为:{fieldName}={fieldValue}不合法,保留位数必须为{BeforePointMaxLength},{AfterPointLength},取值范围为[&gt;{MinValue},&lt;{MaxValue}]</para>
/// </summary>
public override string ErrMsg
{
get
{
if (string.IsNullOrWhiteSpace(_errMsg))
{
//_errMsg = "{fieldName}={fieldValue}不合法,值应为数字,且保留位数必须为[{BeforePointMaxLength},{AfterPointLength}]";
_errMsg = "值应为数字,且保留位数必须为[{BeforePointMaxLength},{AfterPointLength}]";
var msgArr = new List<string>();
if (!double.IsNaN(MinValue))
{
msgArr.Add(">={MinValue}");
}
if (!double.IsNaN(MaxValue))
{
msgArr.Add("<={MaxValue}");
}
if (msgArr.Count > 0)
{
_errMsg += $",取值范围为[{string.Join(",", msgArr)}]";
}
}
return _errMsg;
}
set
{
_errMsg = value;
}
}
protected override bool Execute(string value)
{
if (!double.TryParse(value, out var temp))
{
return false;
}
if (!double.IsNaN(MinValue) && temp < MinValue)
{
return false;
}
if (!double.IsNaN(MaxValue) && temp > MaxValue)
{
return false;
}
var part = (value ?? "").Split('.');
if (part[0].Length > BeforePointMaxLength)
{
return false;
}
if (part.Length == 1 || (part.Length > 1 && part[1].Length != AfterPointLength))
{
var sufix = "0.".PadRight(AfterPointLength + 2, '0');
UseChangeValue = true;
ChangedValue = temp.ToString(sufix);
return true;
}
return true;
}
protected override string GenerateErrMsg(string value)
{
return ErrMsg
.Replace("{fieldValue}", value)
.Replace("{BeforePointMaxLength}", BeforePointMaxLength.ToString())
.Replace("{AfterPointLength}", AfterPointLength.ToString())
.Replace("{MinValue}", MinValue.ToString())
.Replace("{MaxValue}", MaxValue.ToString());
}
}
/// <summary>
/// 检查IEnumerable基类属性基类
/// </summary>
public abstract class BaseCheckIEnumerableTAttribute : BaseCheckAttribute
{
public override bool Execute(object value)
{
var state = false;
var objs = value as IEnumerable<object>;
//if (objs != null)
//{
state = Execute(objs);
//}
if (!state)
{
ErrMsg = GenerateErrMsg(objs);
}
return state;
}
protected abstract string GenerateErrMsg(IEnumerable<object> value);
protected abstract bool Execute(IEnumerable<object> value);
}
/// <summary>
/// 检查列表最小数量
/// </summary>
public sealed class CheckIEnumerableTMinCountAttribute : BaseCheckIEnumerableTAttribute
{
/// <summary>
/// 列表数量
/// </summary>
public int MinCount { get; set; }
private string _errMsg;
/// <summary>
/// 错误提示
/// <para>默认为:{fieldName}.Length={fieldValue}不合法,应大于{MinCount}</para>
/// </summary>
public override string ErrMsg
{
get
{
if (string.IsNullOrWhiteSpace(_errMsg))
{
//_errMsg = "{fieldName}.Length={fieldValue}不合法,数量应大于{MinCount}";
_errMsg = "列表长度={fieldValue}不合法,应大于{MinCount}";
}
return _errMsg;
}
set
{
_errMsg = value;
}
}
protected override bool Execute(IEnumerable<object> value)
{
return value != null && value.Count() >= MinCount;
}
protected override string GenerateErrMsg(IEnumerable<object> value)
{
return ErrMsg.Replace("{fieldValue}", (value?.Count() ?? 0).ToString()).Replace("{MinCount}", MinCount.ToString());
}
}
/// <summary>
/// 检查列表最大数量
/// </summary>
public sealed class CheckIEnumerableTMaxCountAttribute : BaseCheckIEnumerableTAttribute
{
/// <summary>
/// 列表数量
/// </summary>
public int MaxCount { get; set; }
private string _errMsg;
/// <summary>
/// 错误提示
/// <para>默认为:{fieldName}.Length={fieldValue}不合法,应小于等于{MaxCount}</para>
/// </summary>
public override string ErrMsg
{
get
{
if (string.IsNullOrWhiteSpace(_errMsg))
{
//_errMsg = "{fieldName}.Length={fieldValue}不合法,数量应大于{MinCount}";
_errMsg = "列表长度={fieldValue}不合法,应小于等于{MaxCount}";
}
return _errMsg;
}
set
{
_errMsg = value;
}
}
protected override bool Execute(IEnumerable<object> value)
{
return value == null || value.Count() <= MaxCount;
}
protected override string GenerateErrMsg(IEnumerable<object> value)
{
return ErrMsg.Replace("{fieldValue}", (value?.Count() ?? 0).ToString()).Replace("{MaxCount}", MaxCount.ToString());
}
}
/// <summary>
/// 检查字符串是否为指定可选值之一
/// </summary>
public sealed class CheckStringInMapAttribute : BaseCheckStringAttribute
{
/// <summary>
/// 可选值列表
/// </summary>
public string[] Map { get; set; }
private string _errMsg;
/// <summary>
/// 错误提示
/// <para>默认为:{fieldName}={fieldValue}不合法,值应为{Map}之一</para>
/// </summary>
public override string ErrMsg
{
get
{
if (string.IsNullOrWhiteSpace(_errMsg))
{
//_errMsg = "{fieldName}={fieldValue}不合法,值应为{Map}";
_errMsg = "值应为{Map}";
if (Map.Length > 1)
{
_errMsg += "之一";
}
}
return _errMsg;
}
set
{
_errMsg = value;
}
}
protected override bool Execute(string value)
{
return Map.Contains(value ?? "");
}
protected override string GenerateErrMsg(string value)
{
return ErrMsg.Replace("{fieldValue}", value).Replace("{Map}", string.Join(",", Map));
}
}
/// <summary>
/// 检查字符串长度是否为可选值之一
/// </summary>
public sealed class CheckStringLengthInMapAttribute : BaseCheckStringAttribute
{
/// <summary>
/// 可选值列表
/// </summary>
public int[] Map { get; set; }
private string _errMsg;
/// <summary>
/// 错误提示
/// <para>默认为:{fieldName}={fieldValue}不合法,长度应为{Map}之一</para>
/// </summary>
public override string ErrMsg
{
get
{
if (string.IsNullOrWhiteSpace(_errMsg))
{
//_errMsg = "{fieldName}={fieldValue}不合法,值应为{Map}之一";
_errMsg = "内容长度={fieldValue}不合法,长度应为{Map}之一";
}
return _errMsg;
}
set
{
_errMsg = value;
}
}
protected override bool Execute(string value)
{
var length = value.Length;
return Map.Contains(length);
}
protected override string GenerateErrMsg(string value)
{
return ErrMsg.Replace("{fieldValue}", value).Replace("{Map}", string.Join(",", Map));
}
}
#endregion
#region Condition
/// <summary>
/// 检查条件基类
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public abstract class BaseCheckConditionAttribute : Attribute
{
/// <summary>
/// 条件字段名
/// <para>应填写当前对象可访问到的字段</para>
/// </summary>
public string ConditionName { get; set; }
private string[] _checkHandleNameArr;
/// <summary>
/// 绑定满足条件后的处理逻辑
/// <para>不填时依次执行CheckName为空的操作</para>
/// </summary>
public string[] CheckHandleNameArr
{
get
{
if (_checkHandleNameArr == null)
{
return new string[] { null };
}
return _checkHandleNameArr;
}
set
{
_checkHandleNameArr = value;
}
}
public abstract bool Execute(object value);
}
/// <summary>
/// 检查指定字段的值是否等于预设值
/// </summary>
public sealed class CheckConditionStringValueAttribute : BaseCheckConditionAttribute
{
/// <summary>
/// 预设值
/// </summary>
public string ConditionValue { get; set; }
public override bool Execute(object value)
{
return value?.ToString() == ConditionValue;
}
}
/// <summary>
/// 检查指定字段的值是否不等于预设值
/// </summary>
public sealed class CheckConditionStringNEQValueAttribute : BaseCheckConditionAttribute
{
/// <summary>
/// 预设值
/// </summary>
public string ConditionValue { get; set; }
public override bool Execute(object value)
{
return value?.ToString() != ConditionValue;
}
}
/// <summary>
/// 检查指定字段的值是否在范围内
/// </summary>
public sealed class CheckConditionIntInRangeAttribute : BaseCheckConditionAttribute
{
/// <summary>
/// 最小值
/// <para>默认为int.MinValue</para>
/// </summary>
public int MinValue { get; set; } = int.MinValue;
/// <summary>
/// 最大值
/// <para>默认为int.MaxValue</para>
/// </summary>
public int MaxValue { get; set; } = int.MaxValue;
public override bool Execute(object value)
{
if (double.TryParse((value ?? "").ToString(), out var temp))
{
return temp >= MinValue && temp <= MaxValue;
}
return false;
}
}
/// <summary>
/// 检查指定字段的值是否不在范围内
/// </summary>
public sealed class CheckConditionIntNotInRangeValueAttribute : BaseCheckConditionAttribute
{
/// <summary>
/// 最小值
/// <para>默认为int.MinValue</para>
/// </summary>
public int MinValue { get; set; } = int.MinValue;
/// <summary>
/// 最大值
/// <para>默认为int.MaxValue</para>
/// </summary>
public int MaxValue { get; set; } = int.MaxValue;
public override bool Execute(object value)
{
if (double.TryParse((value ?? "").ToString(), out double temp))
{
return temp < MinValue || temp > MaxValue;
}
return false;
}
}
/// <summary>
/// 检查指定字段的值是否为可选值之一
/// </summary>
public sealed class CheckConditionStringInMapAttribute : BaseCheckConditionAttribute
{
public string[] ConditionMap { get; set; }
public override bool Execute(object value)
{
return ConditionMap.Contains(value?.ToString() ?? "");
}
}
/// <summary>
/// 检查指定字段的值是否不为可选值
/// </summary>
public sealed class CheckConditionStringNotInMapAttribute : BaseCheckConditionAttribute
{
public string[] ConditionMap { get; set; }
public override bool Execute(object value)
{
return !ConditionMap.Contains(value?.ToString() ?? "");
}
}
#endregion
/// <summary>
/// 检查帮助类
/// </summary>
/// <typeparam name="T"></typeparam>
public class CheckHelper<T> where T:notnull
{
private readonly PropertyInfo[]? _properties = null;
/// <summary>
/// 属性缓存
/// <para>应通过<see cref="CheckHelper{T}.getPropertyInfos(T)"/>方法访问</para>
/// </summary>
private Dictionary<T, Dictionary<string, object>>? _propertyInfoDict = null;
/// <summary>
/// 检查不通过时回调的委托
/// </summary>
/// <param name="fieldName">字段名</param>
/// <param name="value">字段值</param>
/// <param name="errMsg">错误信息</param>
public delegate void CheckErrorCallback(string fieldName, object value, string errMsg);
public CheckHelper()
{
_properties = typeof(T).GetProperties();
}
private Dictionary<string, object> getPropertyInfos(T obj)
{
_propertyInfoDict ??= new Dictionary<T, Dictionary<string, object>>();
if (!_propertyInfoDict.ContainsKey(obj))
{
_propertyInfoDict[obj] = _properties.ToDictionary(K => K.Name, V => V.GetValue(obj));
}
return _propertyInfoDict[obj];
}
private bool checkCondition(List<BaseCheckConditionAttribute> conditionAttributes, Dictionary<string, object> dict)
{
var state = true;
foreach (var item in conditionAttributes)
{
if (!dict.ContainsKey(item.ConditionName))
{
throw new Exception($"当前对象中不存在 {item.ConditionName} 字段");
}
state = item.Execute(dict[item.ConditionName]);
if (!state)
{
break;
}
}
return state;
}
private bool checkCondition(PropertyInfo pInfo, T obj, Func<string[], bool> callback)
{
var state = true;
var conditionAttrs = pInfo.GetCustomAttributes(typeof(BaseCheckConditionAttribute), true).Cast<BaseCheckConditionAttribute>();
var conditGroup = conditionAttrs.GroupBy(O => O.CheckHandleNameArr == null ? "" : string.Join(",", O.CheckHandleNameArr)).ToDictionary(K => K.Key, V => V.ToList());
if (conditGroup.Count > 0)
{
foreach (var condit in conditGroup)
{
var dict = getPropertyInfos(obj);
state = checkCondition(condit.Value, dict);
if (state)
{
if (!callback(condit.Value[0].CheckHandleNameArr))
{
break;
}
}
}
}
else
{
callback(new[] { "" });
}
return state;
}
private bool checkValue(string checkName, BaseCheckAttribute[] checkAttributes, PropertyInfo pInfo, T obj, out string errMsg)
{
errMsg = "";
var state = true;
var attrs = checkAttributes.Where(O => (O.CheckHandleName ?? "") == checkName);
foreach (var item in attrs)
{
state = item.Execute(pInfo.GetValue(obj));
if (!state)
{
errMsg = item.ErrMsg.Replace("{fieldName}", pInfo.Name);
continue;
}
if (item.UseChangeValue)
{
pInfo.SetValue(obj, item.ChangedValue);
}
}
return state;
}
/// <summary>
/// 执行字段检查
/// </summary>
/// <param name="obj">要检查的对象</param>
/// <param name="callback">检查不通过时的回调</param>
/// <returns></returns>
public bool ExecuteCheck(T obj, CheckErrorCallback callback)
{
var checkState = false;
if (obj == null)
{
return checkState;
}
foreach (var p in _properties)
{
var attr = p.GetCustomAttributes(typeof(BaseCheckAttribute), true).Cast<BaseCheckAttribute>().ToArray();
if (attr.Length == 0)
{ continue; }
checkCondition(p, obj, (checkNames) =>
{
var status = true;
foreach (var item in checkNames)
{
if (!checkValue(item ?? "", attr, p, obj, out var errMsg))
{
callback(p.Name, p.GetValue(obj), errMsg);
status = false;
break;
}
}
return status;
});
}
return checkState;
}
}
}