3

我正在为属性构建自己的库,并且我想检查属性级别是否存在属性。目前我有这个方法很好用:

    public static bool HasPropertyAttribute<T>(this object instance, string propertyName)
    {
        return Attribute.GetCustomAttributes(instance.GetType().GetProperty(propertyName), typeof(T), true).Any();
    }

现在我正在研究允许我将 lambda 表达式而不是字符串作为 propertyName 传递的解决方案。有没有一种优雅的方法来做到这一点,而无需添加此方法以成为依赖于两个泛型类型,即:

HasPropertyAttribute<T, TProperty>(...).
4

2 回答 2

6

您可以使用 Lambda 表达式来解析编译时属性引用。(从 lambda 表达式中检索属性名称修改的代码)

public PropertyInfo GetPropertyInfo<TProperty>(
    Expression<Func<TProperty>> propertyLambda)
{
    MemberExpression member = propertyLambda.Body as MemberExpression;
    if (member == null)
        throw new ArgumentException(string.Format(
            "Expression '{0}' refers to a method, not a property.",
            propertyLambda.ToString()));

    PropertyInfo propInfo = member.Member as PropertyInfo;
    if (propInfo == null)
        throw new ArgumentException(string.Format(
            "Expression '{0}' refers to a field, not a property.",
            propertyLambda.ToString()));

    return propInfo;
}

您不需要将其用作扩展方法(尽管如果您想对其进行调整也可以,但是除了编写该行之外,没有必要拥有源对象实例)

public class Test
{
    public string Prop { get; set; }
}

Test t = new Test();
PropertyInfo propInfo = GetPropertyInfo(() => t.Prop);
Console.WriteLine(propInfo.Name + " -> " + propInfo.PropertyType); //Prop -> System.String

编辑:如果你想有一些不错的语法并且必须避免对类型对象的现有引用,你可以执行以下操作:

public static class TypedReflection<TSource>
{
    public static PropertyInfo GetPropertyInfo<TProperty>(
        Expression<Func<TSource, TProperty>> propertyLambda)
    {
        MemberExpression member = propertyLambda.Body as MemberExpression;
        if (member == null)
            throw new ArgumentException(string.Format(
                "Expression '{0}' refers to a method, not a property.",
                propertyLambda.ToString()));

        PropertyInfo propInfo = member.Member as PropertyInfo;
        if (propInfo == null)
            throw new ArgumentException(string.Format(
                "Expression '{0}' refers to a field, not a property.",
                propertyLambda.ToString()));

        return propInfo;
    }
}

并称它为:

PropertyInfo propInfo = TypedReflection<Test>.GetPropertyInfo(o => o.Prop);

此时,很容易添加额外的类型化反射方法(get 方法、字段等)

编辑:它仍然依赖于两个泛型类型,但它通过类型推断隐藏起来。我更喜欢第二个例子;至少您需要指定声明类类型(因为您需要类型安全),但您不需要对象实例。它还有一个好处(我怀疑你在追求),如果你重命名属性,它会传播到这段代码,获取PropertyInfo.

于 2012-10-25T16:11:59.810 回答
0

我选择了这个解决方案,代码最少:

    public static bool HasPropertyAttribute<T, TProperty>(this T instance, Expression<Func<T, TProperty>> propertySelector, Type attribute)
    {
        return Attribute.GetCustomAttributes(instance.GetType().GetProperty((propertySelector.Body as MemberExpression).Member.Name), attribute, true).Any();
    }

像这样调用:

var cc = new CustomClass();
cc.HasPropertyAttribute(x => x.Name, typeof(NullableAttribute))
于 2012-10-25T16:29:42.810 回答