使用反射通过从setter调用的方法获取属性的属性

时间:2010-09-02 15:28:01

标签: c# .net reflection attributes

注意:这是对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方法

3 个答案:

答案 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;
    }
}