注意:这是对answer 上previous question的跟进。
我正在使用名为TestMaxStringLength
的属性来装饰属性的setter,该属性在setter调用的方法中用于验证。
该属性目前看起来像这样:
public string CompanyName
{
get
{
return this._CompanyName;
}
[TestMaxStringLength(50)]
set
{
this.ValidateProperty(value);
this._CompanyName = value;
}
}
但我希望它看起来像这样:
[TestMaxStringLength(50)]
public string CompanyName
{
get
{
return this._CompanyName;
}
set
{
this.ValidateProperty(value);
this._CompanyName = value;
}
}
负责查找setter属性的ValidateProperty
代码为:
private void ValidateProperty(string value)
{
var attributes =
new StackTrace()
.GetFrame(1)
.GetMethod()
.GetCustomAttributes(typeof(TestMaxStringLength), true);
//Use the attributes to check the length, throw an exception, etc.
}
如何更改ValidateProperty
代码以查找属性上的属性而不是 set方法?
答案 0 :(得分:7)
据我所知,没有办法从其中一个setter的MethodInfo中获取PropertyInfo。当然,虽然你可以使用一些字符串黑客,比如使用查找名称等等。我想的是:
var method = new StackTrace().GetFrame(1).GetMethod();
var propName = method.Name.Remove(0, 4); // remove get_ / set_
var property = method.DeclaringType.GetProperty(propName);
var attribs = property.GetCustomAttributes(typeof(TestMaxStringLength), true);
不用说,这并不完全符合要求。
另外,请小心使用StackTrace类 - 当使用频率太高时,这也是一种性能损失。
答案 1 :(得分:2)
在声明方法的类中,您可以搜索包含该setter的属性。它不是高效的,但StackTrace
也没有。
void ValidateProperty(string value)
{
var setter = (new StackTrace()).GetFrame(1).GetMethod();
var property =
setter.DeclaringType
.GetProperties()
.FirstOrDefault(p => p.GetSetMethod() == setter);
Debug.Assert(property != null);
var attributes = property.GetCustomAttributes(typeof(TestMaxStringLengthAttribute), true);
//Use the attributes to check the length, throw an exception, etc.
}
答案 2 :(得分:2)
作为一种替代方法,您可以考虑将验证推迟到以后,从而无需检查堆栈跟踪。
此示例提供了一个属性...
public class MaxStringLengthAttribute : Attribute
{
public int MaxLength { get; set; }
public MaxStringLengthAttribute(int length) { this.MaxLength = length; }
}
...将属性应用于属性的POCO ...
public class MyObject
{
[MaxStringLength(50)]
public string CompanyName { get; set; }
}
...以及验证对象的实用程序类存根。
public class PocoValidator
{
public static bool ValidateProperties<TValue>(TValue value)
{
var type = typeof(TValue);
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var prop in props)
{
var atts = prop.GetCustomAttributes(typeof(MaxStringLengthAttribute), true);
var propvalue = prop.GetValue(value, null);
// With the atts in hand, validate the propvalue ...
// Return false if validation fails.
}
return true;
}
}