接上篇接手同事代码,新增新的业务类型。每种类型都存到新的数据库表中。
有这么个需求,假设业务类型为A
,数据表为Table_A
,那么就有一张Table_VerifyA
表,用于录入A
的字段校验信息。
看到同事代码的一瞬间,我再次崩溃了,以下是大致的逻辑
foreach (var pi in typeof(Table_A).GetProperties()) {
if (...) {
...
} else {
...
}
if (...) {
...
}
foreach (var p2 in typeof(Table_VerifyA).GetProperties()) {
if (...) {
...
} else {
...
}
if (...) {
...
}
}
}
大致看了下,一个业务表大概有100个字段,800行的ifelse,有够暴力的。。
思考(摸鱼)了一天后,有了点想法
我可以通过Attribute来控制当前字段是否需要校验以及校验方式,所以就有了下面的东西。
/// <summary>
/// 根据字段具体值,初始化校验方法
/// </summary>
/// <param name="value">字段的值</param>
void BuildVerifyRule(object value);
/// <summary>
/// 校验方法
/// </summary>
/// <param name="value">需要校验的值</param>
/// <param name="msg">错误信息</param>
/// <returns>是否通过校验</returns>
bool Test(object value, out string msg);
- 实现
IVerify
的Attribute,例如最小值的判断
public class MinLimitVerifyAttribute : BaseVerify, IVerify {
private int? _min;
public void BuildVerifyRule(object value) {
var p = CheckValue(value);
if (int.TryParse(p, out int m)) {
_min = m;
}
}
public bool Test(object value, out string msg) {
var m = "";
var result = CheckInput(value, input => {
if (int.TryParse(input, out int i)) {
if (_min.HasValue) {
var r = i >= _min;
m = r ? "" : $"数值不匹配!(必须大于等于{_min.Value})";
return r;
} else {
m = "车型库数据非法!";
return false;
}
} else {
m = "非数值!";
return false;
}
});
msg = m;
return result;
}
}
- 在
Table_VerifyA
的实体表上使用Attribute
[MinLimitVerify]
public string AAAA { get; set; }
public class VerifyTool {
Dictionary<string, IVerify> verifies = new Dictionary<string, IVerify>();
public VerifyTool SetRule<T>(T stand) where T : IStandard {
var props = typeof(T).GetProperties();
foreach (PropertyInfo prop in props) {
var attr = prop.GetAttribute<IVerify>();
if (attr == null)
continue;
var value = prop.GetValue(stand, null);
attr.BuildVerifyRule(value);
verifies.Add(prop.Name, attr);
}
return this;
}
public bool Verify(object entity, out string msg) {
var props = entity.GetType().GetProperties();
foreach (PropertyInfo prop in props) {
var name = prop.Name;
var rename = prop.GetAttribute<VerifyNameAttribute>();
var desprition = prop.GetAttribute<DescriptionAttribute>();
if (rename != null)
name = rename.Name;
if (!verifies.ContainsKey(name))
continue;
var vf = verifies[name];
var value = prop.GetValue(entity, null);
if (!vf.Test(value, out string err)) {
var desp = desprition?.Description ?? name;
msg = $"{desp}:{err}";
return false;
}
}
msg = "";
return true;
}
}
if (!verifyTool.SetRule(stand).Verify(entity, out msg)) {
throw new Exception(msg);
}