【发布时间】:2016-03-09 18:05:05
【问题描述】:
背景故事:在整个项目中,我们不断发现自己使用System.ComponentModel.DataAnnotations.Validator 对象以及属性来验证传递给我们 API 的属性。 Validator 对象需要传入属性名称和值,这是公平的,但我们都被传递的[不断增加] 数量的 魔术字符串 搞砸了对于这些属性名称。这不仅会带来错误输入属性名称的风险,还会在其中一个属性被重命名的情况下降低可维护性(同样,它们太多了)。
为了自动解析成员名称,我创建了这个辅助方法(为了简单起见,假设我只处理引用类型的属性,因此有P: class 约束):
public static P ValidateProperty<T, P>(T obj, Expression<Func<T, P>> member, List<ValidationResult> results, Func<P, P> onValidCallback = null)
where T : class
where P : class
{
var expr = member.Compile();
var memberName = ((MemberExpression)member.Body).Member.Name;
var value = expr(obj);
bool isValid = Validator.TryValidateProperty(value, new ValidationContext(obj) { MemberName = memberName }, results);
return isValid ? (onValidCallback != null ? onValidCallback(value) : value) : null;
}
我只是这样称呼它:
var value = ValidateProperty(myObject, x => x.PropertyFoo, errors, result => result.Trim());
这就像一个魅力,不涉及传递任何魔术字符串。
示例请求如下所示:
public class Request
{
public class C1
{
Property1;
Property2;
...
}
public class C2
{
Property1;
Property2;
...
}
public class C3
{
Property1;
Property2;
...
}
...
}
然而,我在这里担心的是member.Compile() 的性能影响。由于T, P 有许多不同的可能排列(C1, Property1、C1, Property2、C2, Property1 等)我将无法缓存已编译的表达式并在下一次调用时执行它,除非T和P 属于同一类型,这种情况很少发生。
我可以通过将Expression<Func<T, P>> member 更改为Expression<Func<T, object>> member 来优化这一点,这样现在我只需将每个T 类型的表达式缓存一次(即C1、C2 等)
我想知道是否有人对更好的方法有任何意见,还是我试图“过度设计”问题?对于一遍又一遍地传递魔术字符串的情况,是否有一种常见的模式?
【问题讨论】:
-
这会让你回到神奇的字符串,但你是否考虑过新的 C#6
nameof运算符而不是 od 表达式? -
伙计,
nameof正是我所需要的,但不幸的是,我们现在被困在 C#5 上......
标签: c# lambda expression-trees