获取[显示名称]属性的属性,强类型的方式 [英] Get [DisplayName] attribute of a property in strongly-typed way

查看:109
本文介绍了获取[显示名称]属性的属性,强类型的方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

美好的一天!

我有这样的方法来获得 [显示名称] 属性的属性值(直接连接或者使用 [MetadataType] 属性)。我用它在极少数情况下,我需要获得 [显示名称] 在控制器code。

 公共静态类MetaDataHelper
{
    公共静态字符串GetDisplayName(类型数据类型的字符串字段名)
    {
        //首先考虑一个类型的属性,它的父母
        DisplayNameAttribute ATTR;
        ATTR = (DisplayNameAttribute)dataType.GetProperty(fieldName).GetCustomAttributes(typeof(DisplayNameAttribute),真).SingleOrDefault();        //寻找的类型层次结构[MetadataType]属性
        // http://stackoverflow.com/questions/1910532/attribute-isdefined-doesnt-see-attributes-applied-with-metadatatype-class
        如果(ATTR == NULL)
        {
            MetadataTypeAttribute metadataType =(MetadataTypeAttribute)dataType.GetCustomAttributes(typeof运算(MetadataTypeAttribute),真).FirstOrDefault();
            如果(metadataType!= NULL)
            {
                VAR财产= metadataType.MetadataClassType.GetProperty(字段名);
                如果(财产!= NULL)
                {
                    ATTR =(DisplayNameAttribute)property.GetCustomAttributes(typeof运算(DisplayNameAttribute),真).SingleOrDefault();
                }
            }
        }
        返回(ATTR!= NULL)? attr.DisplayName:的String.Empty;
    }
}

它的工作原理,但它有两个缺点:


  • 它需要的字段名称为字符串

  • 如果我想获得一个属性
  • 的属性它不工作

是否有可能使用lambda表达式克服这两个问题,像我们在ASP.NET MVC:

  Html.LabelFor(M = GT; m.Property.Can.Be.Very.Complex.But.Strongly.Typed);

更新

下面是从的 BuildStarted 的解决方案的更新和选中的版本。它被修改为使用显示名称属性(如果你使用它,你可以修改回显示属性)。固定小错误得到嵌套属性的属性。

 公共静态字符串GetDisplayName<的TModel>(防爆pression< Func键<的TModel,对象>>前pression)
{
    类型type = typeof运算(的TModel);    字符串参数propertyName = NULL;
    字符串[]属性= NULL;
    IEnumerable的<串GT; propertyList;
    //除非它是一个根本性质的前pression的NodeType将永远转换
    开关(如pression.Body.NodeType)
    {
        案例防爆pressionType.Convert:
        案例防爆pressionType.ConvertChecked:
            VAR UE =前pression.Body作为UnaryEx pression;
            propertyList =(!?UE = NULL ue.Operand:零)。的ToString()分裂(。。ToCharArray())跳过(1); //不要使用root属性
            打破;
        默认:
            propertyList =前pression.Body.ToString()斯普利特(ToCharArray()。)跳过(1)。
            打破;
    }    //将PROPERT名字就是我们所追求的
    参数propertyName = propertyList.Last();
    //属性列表 - 最后一个属性名
    属性= propertyList.Take(propertyList.Count() - 1).ToArray(); //抓住所有的父属性    的foreach(在属性字符串属性)
    {
        的PropertyInfo的PropertyInfo = type.GetProperty(财产);
        键入= propertyInfo.PropertyType;
    }    DisplayNameAttribute ATTR;
    ATTR = (DisplayNameAttribute)type.GetProperty(propertyName).GetCustomAttributes(typeof(DisplayNameAttribute),真).SingleOrDefault();    //寻找的类型层次结构[MetadataType]属性
    // http://stackoverflow.com/questions/1910532/attribute-isdefined-doesnt-see-attributes-applied-with-metadatatype-class
    如果(ATTR == NULL)
    {
        MetadataTypeAttribute metadataType =(MetadataTypeAttribute)type.GetCustomAttributes(typeof运算(MetadataTypeAttribute),真).FirstOrDefault();
        如果(metadataType!= NULL)
        {
            VAR财产= metadataType.MetadataClassType.GetProperty(propertyName的);
            如果(财产!= NULL)
            {
                ATTR =(DisplayNameAttribute)property.GetCustomAttributes(typeof运算(DisplayNameAttribute),真).SingleOrDefault();
            }
        }
    }
    返回(ATTR!= NULL)? attr.DisplayName:的String.Empty;
}


解决方案

有两种方法可以做到这一点:

  Models.Test测试=新Models.Test();
字符串显示名称= test.GetDisplayName(T => t.Name);字符串显示名称= Helpers.GetDisplayName< Models.Test>(T => t.Name);

第一个作品凭借写一个通用的扩展方法来任何的TModel(这是所有类型)的。这意味着,这将是可用的任何对象,而不仅仅是你的模型。并不推荐使用,但因为它的漂亮简洁的语法。

第二种方法需要您在模型中它的类型传递 - 这你已经在做,但是作为参数来代替。该方法需要通过泛型定义类型,因为Func键期待吧。

下面是方法,你要退房。

静态扩展方法对所有对象

 公共静态字符串GetDisplayName<的TModel,TProperty>(这种tModel模式,防爆pression< Func键<的TModel,TProperty>>前pression){    类型type = typeof运算(的TModel);    MemberEx pression memberEx pression =(MemberEx pression)前pression.Body;
    字符串参数propertyName =((memberEx pression.Member是的PropertyInfo)memberEx pression.Member.Name:NULL);    //首先考虑一个类型的属性,它的父母
    DisplayAttribute ATTR;
    ATTR =(DisplayAttribute)type.GetProperty(propertyName的).GetCustomAttributes(typeof运算(DisplayAttribute),真).SingleOrDefault();    //寻找的类型层次结构[MetadataType]属性
    // http://stackoverflow.com/questions/1910532/attribute-isdefined-doesnt-see-attributes-applied-with-metadatatype-class
    如果(ATTR == NULL){
        MetadataTypeAttribute metadataType =(MetadataTypeAttribute)type.GetCustomAttributes(typeof运算(MetadataTypeAttribute),真).FirstOrDefault();
        如果(metadataType!= NULL){
            VAR财产= metadataType.MetadataClassType.GetProperty(propertyName的);
            如果(财产!= NULL){
                ATTR =(DisplayAttribute)property.GetCustomAttributes(typeof运算(DisplayNameAttribute),真).SingleOrDefault();
            }
        }
    }
    返回(ATTR!= NULL)? attr.Name:的String.Empty;
}

签名类型具体方法 - 同code如上只是不同的呼叫

 公共静态字符串GetDisplayName<的TModel>(防爆pression< Func键<的TModel,对象>>前pression){}

你不能只用其原因 Something.GetDisplayName(T =&GT; t.Name)在它自己是因为在剃刀引擎,你实际上是在传递这只是需要编译器来推断哪种类型属于哪一个通用名称< - 这也是为什么第一种方法需要一个实例化的对象;的TModel&gt;将的HtmlHelper℃的实例化对象/ p>

更新递归特性

 公共静态字符串GetDisplayName&LT;的TModel&GT;(防爆pression&LT; Func键&LT;的TModel,对象&gt;&GT;前pression){    类型type = typeof运算(的TModel);    字符串参数propertyName = NULL;
    字符串[]属性= NULL;
    IEnumerable的&LT;串GT; propertyList;
    //除非它是一个根本性质的前pression的NodeType将永远转换
    开关(如pression.Body.NodeType){
        案例防爆pressionType.Convert:
        案例防爆pressionType.ConvertChecked:
            VAR UE =前pression.Body作为UnaryEx pression;
            propertyList =(!?UE = NULL ue.Operand:零)。的ToString()分裂(。。ToCharArray())跳过(1); //不要使用root属性
            打破;
        默认:
            propertyList =前pression.Body.ToString()斯普利特(ToCharArray()。)跳过(1)。
            打破;
    }    //将PROPERT名字就是我们所追求的
    参数propertyName = propertyList.Last();
    //属性列表 - 最后一个属性名
    属性= propertyList.Take(propertyList.Count() - 1).ToArray(); //抓住所有的父属性    防爆pression EXPR = NULL;
    的foreach(在属性字符串属性){
        的PropertyInfo的PropertyInfo = type.GetProperty(财产);
        EXPR =前pression.Property(表达式,type.GetProperty(属性));
        键入= propertyInfo.PropertyType;
    }    DisplayAttribute ATTR;
    ATTR =(DisplayAttribute)type.GetProperty(propertyName的).GetCustomAttributes(typeof运算(DisplayAttribute),真).SingleOrDefault();    //寻找的类型层次结构[MetadataType]属性
    // http://stackoverflow.com/questions/1910532/attribute-isdefined-doesnt-see-attributes-applied-with-metadatatype-class
    如果(ATTR == NULL){
        MetadataTypeAttribute metadataType =(MetadataTypeAttribute)type.GetCustomAttributes(typeof运算(MetadataTypeAttribute),真).FirstOrDefault();
        如果(metadataType!= NULL){
            VAR财产= metadataType.MetadataClassType.GetProperty(propertyName的);
            如果(财产!= NULL){
                ATTR =(DisplayAttribute)property.GetCustomAttributes(typeof运算(DisplayNameAttribute),真).SingleOrDefault();
            }
        }
    }
    返回(ATTR!= NULL)? attr.Name:的String.Empty;}

Good day!

I've such method to get [DisplayName] attribute value of a property (which is attached directly or using [MetadataType] attribute). I use it in rare cases where I need to get [DisplayName] in controller code.

public static class MetaDataHelper
{
    public static string GetDisplayName(Type dataType, string fieldName)
    {       
        // First look into attributes on a type and it's parents
        DisplayNameAttribute attr;
        attr = (DisplayNameAttribute)dataType.GetProperty(fieldName).GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();

        // Look for [MetadataType] attribute in type hierarchy
        // http://stackoverflow.com/questions/1910532/attribute-isdefined-doesnt-see-attributes-applied-with-metadatatype-class
        if (attr == null)
        {
            MetadataTypeAttribute metadataType = (MetadataTypeAttribute)dataType.GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault();
            if (metadataType != null)
            {
                var property = metadataType.MetadataClassType.GetProperty(fieldName);
                if (property != null)
                {
                    attr = (DisplayNameAttribute)property.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();
                }
            }
        }
        return (attr != null) ? attr.DisplayName : String.Empty;
    }
}

It works, but it has two drawbacks:

  • It requires field name as string
  • It doesn't work if I want to get property of a property

Is it possible to overcome both problems using lambdas, something like we have in ASP.NET MVC:

Html.LabelFor(m => m.Property.Can.Be.Very.Complex.But.Strongly.Typed);  

Update

Here is an updated and checked version from BuildStarted solution. It is modified to use DisplayName attribute (you can modify back to Display attribute if you use it). And fixed minor bugs to get attribute of nested properties.

public static string GetDisplayName<TModel>(Expression<Func<TModel, object>> expression)
{
    Type type = typeof(TModel);

    string propertyName = null;
    string[] properties = null;
    IEnumerable<string> propertyList;
    //unless it's a root property the expression NodeType will always be Convert
    switch (expression.Body.NodeType)
    {
        case ExpressionType.Convert:
        case ExpressionType.ConvertChecked:
            var ue = expression.Body as UnaryExpression;
            propertyList = (ue != null ? ue.Operand : null).ToString().Split(".".ToCharArray()).Skip(1); //don't use the root property
            break;
        default:
            propertyList = expression.Body.ToString().Split(".".ToCharArray()).Skip(1);
            break;
    }

    //the propert name is what we're after
    propertyName = propertyList.Last();
    //list of properties - the last property name
    properties = propertyList.Take(propertyList.Count() - 1).ToArray(); //grab all the parent properties

    foreach (string property in properties)
    {
        PropertyInfo propertyInfo = type.GetProperty(property);
        type = propertyInfo.PropertyType;
    }

    DisplayNameAttribute attr;
    attr = (DisplayNameAttribute)type.GetProperty(propertyName).GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();

    // Look for [MetadataType] attribute in type hierarchy
    // http://stackoverflow.com/questions/1910532/attribute-isdefined-doesnt-see-attributes-applied-with-metadatatype-class
    if (attr == null)
    {
        MetadataTypeAttribute metadataType = (MetadataTypeAttribute)type.GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault();
        if (metadataType != null)
        {
            var property = metadataType.MetadataClassType.GetProperty(propertyName);
            if (property != null)
            {
                attr = (DisplayNameAttribute)property.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();
            }
        }
    }
    return (attr != null) ? attr.DisplayName : String.Empty;
}

解决方案

There are two ways to do this:

Models.Test test = new Models.Test();
string DisplayName = test.GetDisplayName(t => t.Name);

string DisplayName = Helpers.GetDisplayName<Models.Test>(t => t.Name);

The first one works by virtue of writing a generic extension method to any TModel (which is all types). This means it will be available on any object and not just your model. Not really recommended but nice because of it's concise syntax.

The second method requires you to pass in the Type of the model it is - which you're already doing but as a parameter instead. This method is required to define type via Generics because Func expects it.

Here are the methods for you to check out.

Static extension method to all objects

public static string GetDisplayName<TModel, TProperty>(this TModel model, Expression<Func<TModel, TProperty>> expression) {

    Type type = typeof(TModel);

    MemberExpression memberExpression = (MemberExpression)expression.Body;
    string propertyName = ((memberExpression.Member is PropertyInfo) ? memberExpression.Member.Name : null);

    // First look into attributes on a type and it's parents
    DisplayAttribute attr;
    attr = (DisplayAttribute)type.GetProperty(propertyName).GetCustomAttributes(typeof(DisplayAttribute), true).SingleOrDefault();

    // Look for [MetadataType] attribute in type hierarchy
    // http://stackoverflow.com/questions/1910532/attribute-isdefined-doesnt-see-attributes-applied-with-metadatatype-class
    if (attr == null) {
        MetadataTypeAttribute metadataType = (MetadataTypeAttribute)type.GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault();
        if (metadataType != null) {
            var property = metadataType.MetadataClassType.GetProperty(propertyName);
            if (property != null) {
                attr = (DisplayAttribute)property.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();
            }
        }
    }
    return (attr != null) ? attr.Name : String.Empty;


}

Signature for type specific method - same code as above just different call

public static string GetDisplayName<TModel>(Expression<Func<TModel, object>> expression) { }

The reason you can't just use Something.GetDisplayName(t => t.Name) on it's own is because in the Razor engine you're actually passing an instantiated object of HtmlHelper<TModel> which is why the first method requires an instantiated object - This is only required for the compiler to infer what types belong to which generic name.

Update with recursive properties

public static string GetDisplayName<TModel>(Expression<Func<TModel, object>> expression) {

    Type type = typeof(TModel);

    string propertyName = null;
    string[] properties = null;
    IEnumerable<string> propertyList;
    //unless it's a root property the expression NodeType will always be Convert
    switch (expression.Body.NodeType) {
        case ExpressionType.Convert:
        case ExpressionType.ConvertChecked:
            var ue = expression.Body as UnaryExpression;
            propertyList = (ue != null ? ue.Operand : null).ToString().Split(".".ToCharArray()).Skip(1); //don't use the root property
            break;
        default:
            propertyList = expression.Body.ToString().Split(".".ToCharArray()).Skip(1);
            break;
    }

    //the propert name is what we're after
    propertyName = propertyList.Last();
    //list of properties - the last property name
    properties = propertyList.Take(propertyList.Count() - 1).ToArray(); //grab all the parent properties

    Expression expr = null;
    foreach (string property in properties) {
        PropertyInfo propertyInfo = type.GetProperty(property);
        expr = Expression.Property(expr, type.GetProperty(property));
        type = propertyInfo.PropertyType;
    }

    DisplayAttribute attr;
    attr = (DisplayAttribute)type.GetProperty(propertyName).GetCustomAttributes(typeof(DisplayAttribute), true).SingleOrDefault();

    // Look for [MetadataType] attribute in type hierarchy
    // http://stackoverflow.com/questions/1910532/attribute-isdefined-doesnt-see-attributes-applied-with-metadatatype-class
    if (attr == null) {
        MetadataTypeAttribute metadataType = (MetadataTypeAttribute)type.GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault();
        if (metadataType != null) {
            var property = metadataType.MetadataClassType.GetProperty(propertyName);
            if (property != null) {
                attr = (DisplayAttribute)property.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault();
            }
        }
    }
    return (attr != null) ? attr.Name : String.Empty;



}

这篇关于获取[显示名称]属性的属性,强类型的方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆