2010-03-25 2 views
38

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

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

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

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

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

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

из бетона класса Defination

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 
     } 

ответ

25

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

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

Замечания

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

+0

Searching цепь, предоставление параметра наследования pi.GetCustomAttributes (typeof (NoHtmlOutp ut), true) –

+0

Прочтите замечания. PropertyInfo.GetCustomAttributes() * игнорирует * параметр inherit. – womp

+2

Ничего ... Microsoft должна была поместить его в наименьшее возможное лицо –

0

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

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 
55

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

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); 
+1

Это должен быть ответ. Переход от 'mytype.GetCustomAttributes()' к 'System.Attribute.GetCustomAttribute()' делает параметр 'inherit' таким же, как и предполагалось. Магия! – nathanchere

+2

Не работает для меня в .NET 4.6.1. Попытка получить атрибут из класса POCO динамического прокси-сервера Entity Framework (базовым типом которого является класс POCO). – AyCabron

+0

Это должен быть пользовательский атрибут. Что-то вроде 'DataMemberAttribute' не будет отображаться. – lordcheeto

0

Вот моя попытка. Это метод расширения на 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); 
    } 
} 
0

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

PropertyInfo::GetCustomAttributes<T>(true) 

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

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

System.Attribute.GetCustomAttributes 
Смежные вопросы