Доступ к объявлению Page Factory с использованием [duplicate]

Другим сценарием является то, что вы нанесли нулевой объект в тип значения . Например, код ниже:

object o = null;
DateTime d = (DateTime)o;

Он выкинет NullReferenceException в роли. В приведенном выше примере это кажется совершенно очевидным, но это может произойти в более «поздних связующих» сложных сценариях, где нулевой объект был возвращен из некоторого кода, которого вы не являетесь, и приведение, например, генерируется некоторой автоматической системой.

Одним из примеров этого является этот простой фрагмент привязки ASP.NET с элементом управления календарем:

" />

Здесь SelectedDate на самом деле является свойством - типа DateTime - типа Calendar Web Control, и привязка может отлично вернуть что-то null. Неявный генератор ASP.NET создаст кусок кода, который будет эквивалентен приведенному выше методу. И это поднимет NullReferenceException, что довольно сложно определить, потому что он лежит в сгенерированном ASP.NET коде, который компилирует отлично ...

170
задан developerdoug 9 July 2011 в 22:45
поделиться

13 ответов

Используйте typeof(Book).GetProperties(), чтобы получить массив экземпляров PropertyInfo. Затем используйте GetCustomAttribute() для каждого PropertyInfo, чтобы увидеть, есть ли у каждого из них тип атрибута Author. Если это так, вы можете получить имя свойства из информации о свойствах и значений атрибутов из атрибута.

Что-то в этих строках для сканирования типа свойств, имеющих определенный тип атрибута, и возврата данные в словаре (обратите внимание, что это можно сделать более динамичным, передав типы в подпрограмму):

public static Dictionary<string, string> GetAuthors()
{
    Dictionary<string, string> _dict = new Dictionary<string, string>();

    PropertyInfo[] props = typeof(Book).GetProperties();
    foreach (PropertyInfo prop in props)
    {
        object[] attrs = prop.GetCustomAttributes(true);
        foreach (object attr in attrs)
        {
            AuthorAttribute authAttr = attr as AuthorAttribute;
            if (authAttr != null)
            {
                string propName = prop.Name;
                string auth = authAttr.Name;

                _dict.Add(propName, auth);
            }
        }
    }

    return _dict;
}
208
ответ дан Sнаđошƒаӽ 22 August 2018 в 19:57
поделиться
  • 1
    Я надеялся, что мне не придется бросать атрибут. – developerdoug 9 July 2011 в 23:14
  • 2
    prop.GetCustomAttributes (true) возвращает объект []. Если вы не хотите бросать, вы можете использовать отражение самих экземпляров атрибута. – Adam Markowitz 9 July 2011 в 23:37
  • 3
    Что такое AuthorAttribute здесь? Это класс, который получен из атрибута? @Adam Markowitz – Sarath Avanavu 6 December 2014 в 08:32
  • 4
    Да. OP использует пользовательский атрибут с именем «Автор». См. Здесь пример: msdn.microsoft.com/en-us/library/sw480ze8.aspx – Adam Markowitz 6 December 2014 в 22:03
  • 5
    Стоимость выполнения приведения атрибута совершенно незначителен по сравнению с любой другой задействованной операцией (кроме нулевой проверки и назначения строк). – SilentSin 21 November 2017 в 06:26
foreach (var p in model.GetType().GetProperties())
{
   var valueOfDisplay = 
       p.GetCustomAttributesData()
        .Any(a => a.AttributeType.Name == "DisplayNameAttribute") ? 
            p.GetCustomAttribute<DisplayNameAttribute>().DisplayName : 
            p.Name;
}

В этом примере я использовал DisplayName вместо Author, потому что у него есть поле с именем DisplayName, которое будет отображаться со значением.

0
ответ дан Andrea 22 August 2018 в 19:57
поделиться

Просто ищите подходящее место для размещения этого фрагмента кода.

предположим, что у вас есть следующее свойство:

[Display(Name = "Solar Radiation (Average)", ShortName = "SolarRadiationAvg")]
public int SolarRadiationAvgSensorId { get; set; }

И вы хотите получить значение ShortName. Вы можете сделать:

((DisplayAttribute)(typeof(SensorsModel).GetProperty(SolarRadiationAvgSensorId).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName;

Или сделать его общим:

internal static string GetPropertyAttributeShortName(string propertyName)
{
    return ((DisplayAttribute)(typeof(SensorsModel).GetProperty(propertyName).GetCustomAttribute(typeof(DisplayAttribute)))).ShortName;
}
0
ответ дан Asaf 22 August 2018 в 19:57
поделиться

Вы можете использовать GetCustomAttributesData() и GetCustomAttributes() :

var attributeData = typeof(Book).GetProperty("Name").GetCustomAttributesData();
var attributes = typeof(Book).GetProperty("Name").GetCustomAttributes(false);
15
ответ дан BrokenGlass 22 August 2018 в 19:57
поделиться
  • 1
    какая разница? – Prime By Design 12 April 2016 в 16:07
  • 2
    @PrimeByDesign. Первый обнаруживает как для создания прикладных атрибутов. Последний фактически создает эти атрибуты. – HappyNomad 31 August 2016 в 22:45

Вот некоторые статические методы, которые вы можете использовать для получения MaxLength или любого другого атрибута.

using System;
using System.Linq;
using System.Reflection;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;

public static class AttributeHelpers {

public static Int32 GetMaxLength<T>(Expression<Func<T,string>> propertyExpression) {
    return GetPropertyAttributeValue<T,string,MaxLengthAttribute,Int32>(propertyExpression,attr => attr.Length);
}

//Optional Extension method
public static Int32 GetMaxLength<T>(this T instance,Expression<Func<T,string>> propertyExpression) {
    return GetMaxLength<T>(propertyExpression);
}


//Required generic method to get any property attribute from any class
public static TValue GetPropertyAttributeValue<T, TOut, TAttribute, TValue>(Expression<Func<T,TOut>> propertyExpression,Func<TAttribute,TValue> valueSelector) where TAttribute : Attribute {
    var expression = (MemberExpression)propertyExpression.Body;
    var propertyInfo = (PropertyInfo)expression.Member;
    var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute),true).FirstOrDefault() as TAttribute;

    if (attr==null) {
        throw new MissingMemberException(typeof(T).Name+"."+propertyInfo.Name,typeof(TAttribute).Name);
    }

    return valueSelector(attr);
}

}

Использование статического метода ...

var length = AttributeHelpers.GetMaxLength<Player>(x => x.PlayerName);

Или используя необязательный метод расширения для экземпляра ...

var player = new Player();
var length = player.GetMaxLength(x => x.PlayerName);

Или используя полный статический метод для любого другого атрибута (например, StringLength) ...

var length = AttributeHelpers.GetPropertyAttributeValue<Player,string,StringLengthAttribute,Int32>(prop => prop.PlayerName,attr => attr.MaximumLength);

Вдохновленный ответ Микаэля Энгвера.

0
ответ дан Carter Medlin 22 August 2018 в 19:57
поделиться
private static Dictionary<string, string> GetAuthors()
{
    return typeof(Book).GetProperties()
        .SelectMany(prop => prop.GetCustomAttributes())
        .OfType<AuthorAttribute>()
        .ToDictionary(attribute => attribute.Name, attribute => attribute.Name);
}
3
ответ дан dee 22 August 2018 в 19:57
поделиться

Если вы имеете в виду «для атрибутов, которые принимают один параметр, укажите имена атрибутов и значение параметра», то это проще в .NET 4.5 с помощью API CustomAttributeData:

using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

public static class Program
{
    static void Main()
    {
        PropertyInfo prop = typeof(Foo).GetProperty("Bar");
        var vals = GetPropertyAttributes(prop);
        // has: DisplayName = "abc", Browsable = false
    }
    public static Dictionary<string, object> GetPropertyAttributes(PropertyInfo property)
    {
        Dictionary<string, object> attribs = new Dictionary<string, object>();
        // look for attributes that takes one constructor argument
        foreach (CustomAttributeData attribData in property.GetCustomAttributesData()) 
        {

            if(attribData.ConstructorArguments.Count == 1)
            {
                string typeName = attribData.Constructor.DeclaringType.Name;
                if (typeName.EndsWith("Attribute")) typeName = typeName.Substring(0, typeName.Length - 9);
                attribs[typeName] = attribData.ConstructorArguments[0].Value;
            }

        }
        return attribs;
    }
}

class Foo
{
    [DisplayName("abc")]
    [Browsable(false)]
    public string Bar { get; set; }
}
11
ответ дан Marc Gravell 22 August 2018 в 19:57
поделиться

Я решил аналогичные проблемы, написав вспомогательный атрибут свойства универсального расширения:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

public static class AttributeHelper
{
    public static TValue GetPropertyAttributeValue<T, TOut, TAttribute, TValue>(
        Expression<Func<T, TOut>> propertyExpression, 
        Func<TAttribute, TValue> valueSelector) 
        where TAttribute : Attribute
    {
        var expression = (MemberExpression) propertyExpression.Body;
        var propertyInfo = (PropertyInfo) expression.Member;
        var attr = propertyInfo.GetCustomAttributes(typeof(TAttribute), true).FirstOrDefault() as TAttribute;
        return attr != null ? valueSelector(attr) : default(TValue);
    }
}

Использование:

var author = AttributeHelper.GetPropertyAttributeValue<Book, string, AuthorAttribute, string>(prop => prop.Name, attr => attr.Author);
// author = "AuthorName"
15
ответ дан Mikael Engver 22 August 2018 в 19:57
поделиться
  • 1
    Как я могу получить атрибут description из const Fields? – Amir 2 November 2015 в 20:44
  • 2
    Вы получите: Ошибка 1775 Member 'Namespace.FieldName' не может быть доступна с ссылкой на экземпляр; квалифицируйте его вместо имени типа. Если вам нужно это сделать, я предлагаю изменить «const» на «readonly». – Mikael Engver 3 November 2015 в 10:47
  • 3
    Честно говоря, у вас должно быть гораздо больше полезного голоса. Это очень хороший и полезный ответ во многих случаях. – David Létourneau 14 January 2016 в 17:26
  • 4
    Спасибо @ DavidLétourneau! Можно только надеяться. Кажется, что вы немного помогли в этом. – Mikael Engver 14 January 2016 в 20:39
  • 5
    :) Считаете ли вы возможным иметь значение всех атрибутов для одного класса, используя свой общий метод и присваивая значение атрибута каждому свойству? – David Létourneau 15 January 2016 в 19:51

, чтобы получить атрибут из enum, я использую:

 public enum ExceptionCodes
 {
  [ExceptionCode(1000)]
  InternalError,
 }

 public static (int code, string message) Translate(ExceptionCodes code)
        {
            return code.GetType()
            .GetField(Enum.GetName(typeof(ExceptionCodes), code))
            .GetCustomAttributes(false).Where((attr) =>
            {
                return (attr is ExceptionCodeAttribute);
            }).Select(customAttr =>
            {
                var attr = (customAttr as ExceptionCodeAttribute);
                return (attr.Code, attr.FriendlyMessage);
            }).FirstOrDefault();
        }

// Используя

 var _message = Translate(code);
0
ответ дан Mohamed.Abdo 22 August 2018 в 19:57
поделиться

ЕСЛИ вы просто хотите одно конкретное значение атрибута. Например, атрибут отображения вы можете использовать следующий код.

var pInfo = typeof(Book).GetProperty("Name")
                             .GetCustomAttribute<DisplayAttribute>();
var name = pInfo.Name;
26
ответ дан R2D2 22 August 2018 в 19:57
поделиться

Чтобы получить все атрибуты свойства в словаре, используйте это:

typeof(Book)
  .GetProperty("Name")
  .GetCustomAttributes(false)
  .ToDictionary(a => a.GetType().Name, a => a);

не забудьте изменить значение false на true, если вы хотите также включать в себя наследуемые атрибуты.

83
ответ дан Shimmy 22 August 2018 в 19:57
поделиться
  • 1
    Это делает то же самое, что и решение Адама, но гораздо более кратким. – Daniel Moore 9 July 2011 в 23:58
  • 2
    Добавляйте .OfType & lt; AuthorAttribue & gt; () к выражению вместо ToDictionary, если вам нужны только атрибуты Author и вы хотите пропустить следующий бросок – Adrian Zanescu 27 September 2013 в 10:03
  • 3
    Не будет ли это исключение, если в одном и том же свойстве есть два атрибута одного типа? – Konstantin 2 February 2017 в 17:46

Necromancing. Для тех, кому еще нужно поддерживать .NET 2.0 или тех, которые хотят это сделать без LINQ:

public static object GetAttribute(System.Reflection.MemberInfo mi, System.Type t)
{
    object[] objs = mi.GetCustomAttributes(t, true);

    if (objs == null || objs.Length < 1)
        return null;

    return objs[0];
}



public static T GetAttribute<T>(System.Reflection.MemberInfo mi)
{
    return (T)GetAttribute(mi, typeof(T));
}


public delegate TResult GetValue_t<in T, out TResult>(T arg1);

public static TValue GetAttributValue<TAttribute, TValue>(System.Reflection.MemberInfo mi, GetValue_t<TAttribute, TValue> value) where TAttribute : System.Attribute
{
    TAttribute[] objAtts = (TAttribute[])mi.GetCustomAttributes(typeof(TAttribute), true);
    TAttribute att = (objAtts == null || objAtts.Length < 1) ? default(TAttribute) : objAtts[0];
    // TAttribute att = (TAttribute)GetAttribute(mi, typeof(TAttribute));

    if (att != null)
    {
        return value(att);
    }
    return default(TValue);
}

Пример использования:

System.Reflection.FieldInfo fi = t.GetField("PrintBackground");
wkHtmlOptionNameAttribute att = GetAttribute<wkHtmlOptionNameAttribute>(fi);
string name = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, delegate(wkHtmlOptionNameAttribute a){ return a.Name;});

или просто

string aname = GetAttributValue<wkHtmlOptionNameAttribute, string>(fi, a => a.Name );
1
ответ дан Stefan Steiger 22 August 2018 в 19:57
поделиться
public static class PropertyInfoExtensions
{
    public static TValue GetAttributValue<TAttribute, TValue>(this PropertyInfo prop, Func<TAttribute, TValue> value) where TAttribute : Attribute
    {
        var att = prop.GetCustomAttributes(
            typeof(TAttribute), true
            ).FirstOrDefault() as TAttribute;
        if (att != null)
        {
            return value(att);
        }
        return default(TValue);
    }
}

Использование:

 //get class properties with attribute [AuthorAttribute]
        var props = typeof(Book).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(AuthorAttribute)));
            foreach (var prop in props)
            {
               string value = prop.GetAttributValue((AuthorAttribute a) => a.Name);
            }

или:

 //get class properties with attribute [AuthorAttribute]
        var props = typeof(Book).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(AuthorAttribute)));
        IList<string> values = props.Select(prop => prop.GetAttributValue((AuthorAttribute a) => a.Name)).Where(attr => attr != null).ToList();
1
ответ дан Victor 22 August 2018 в 19:57
поделиться