Наследование пользовательских атрибутов по абстрактным свойствам

У меня есть пользовательский атрибут, который я хочу применить к базовому абстрактному классу, чтобы я мог пропускать элементы, которые не нужно просматривать пользователю при отображении элемента в HTML. Кажется, что свойства, переопределяющие базовый класс, не наследуют атрибуты.

Заменяет ли базовые свойства (абстрактные или виртуальные) атрибуты, отнесенные к исходному свойству?

От класса атрибута Defination

[AttributeUsage(AttributeTargets.Property,
                Inherited = true,
                AllowMultiple = false)]
public class NoHtmlOutput : Attribute
{
}

От абстрактного класса Defination

[NoHtmlOutput]
public abstract Guid UniqueID { get; set; }

От определения класса бетона

public override Guid UniqueID{ get{ return MasterId;} set{MasterId = value;}}

От проверки класса для атрибута

        Type t = o.GetType();
        foreach (PropertyInfo pi in t.GetProperties())
        {
            if (pi.GetCustomAttributes(typeof(NoHtmlOutput), true).Length == 1)
                continue;
            // processing logic goes here
        }

Ответ 1

Нет, атрибуты наследуются.

Это метод GetCustomAttributes(), который не рассматривает родительские объявления. Он рассматривает только атрибуты, применяемые к указанному элементу. Из документов:

Примечание

Этот метод игнорирует наследование параметр для свойств и событий. Поиск цепочки наследования для атрибуты свойств и событий, используйте соответствующие перегрузки Атрибут..::. GetCustomAttributes Метод.

Ответ 2

Вместо вызова PropertyInfo.GetCustomAttributes(...) вы должны вызвать статический метод System.Attribute.GetCustomAttributes(pi,...), как в:

PropertyInfo info = GetType().GetProperties();

// this gets only the attributes in the derived class and ignores the 'true' parameter
object[] DerivedAttributes = info.GetCustomAttributes(typeof(MyAttribute),true);

// this gets all of the attributes up the heirarchy
object[] InheritedAttributes = System.Attribute.GetCustomAttributes(info,typeof(MyAttribute),true);

Ответ 3

Похоже, что это происходит только тогда, когда метод переопределения также имеет атрибут.

http://msdn.microsoft.com/en-us/library/a19191fh.aspx

Однако вы можете переопределить атрибуты того же типа или применить дополнительные атрибуты к производному компоненту. Следующий фрагмент кода показывает настраиваемый элемент управления, который переопределяет свойство Text, унаследованное от элемента управления, путем переопределения атрибута BrowsableAttribute, применяемого в базовом классе. Visual Basic

Public Class MyControl
   Inherits Control
   ' The base class has [Browsable(true)] applied to the Text property.
   <Browsable(False)>  _
   Public Overrides Property [Text]() As String
      ...
   End Property 
   ...
End Class

Ответ 4

Вот моя попытка. Это метод расширения на MemberInfo, который вручную поднимает иерархию наследования. Это похоже на совместимость с динамическими прокси-серверами... по крайней мере, шлангом, созданным Castle, так что я предполагаю, что он будет совместим с любой прокси-библиотекой.

public static IEnumerable<T> GetCustomAttributes<T>(this MemberInfo instance)
{
    while (instance != null)
    {
        object[] attributes = instance.GetCustomAttributes(typeof(T), false);
        if (attributes.Length > 0)
        {
            return attributes.Cast<T>();
        }
        Type ancestor = instance.DeclaringType.BaseType;
        if (ancestor != null)
        {
            IEnumerable<MemberInfo> ancestormatches = ancestor.FindMembers(instance.MemberType, BindingFlags.Instance | BindingFlags.Public, 
                (m, s) =>
                {
                    return m.Name == (string)s;
                }, instance.Name);
            instance = ancestormatches.FirstOrDefault();
        }
        else
        {
            instance = null;
        }
    }
    return new T[] { };
}

И вы бы использовали его вот так.

Type t = o.GetType();
foreach (PropertyInfo pi in t.GetProperties())
{
    IEnumerable<NoHtmlOutput> attributes = pi.GetCustomAttributes<NoHtmlOutput>();
    foreach (NoHtmlOutput attribute in attributes)
    {
      Console.WriteLine(attribute);
    }
}

Ответ 5

Вы можете использовать

PropertyInfo::GetCustomAttributes<T>(true)

который отлично работает, см. пример: https://dotnetfiddle.net/2IhEWH

поэтому нет необходимости использовать статический метод

System.Attribute.GetCustomAttributes