Может ли class C # наследовать атрибуты из своего интерфейса?

Это, по-видимому, означает «нет». К сожалению.

[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, AllowMultiple = true, Inherited = true)] public class CustomDescriptionAttribute : Attribute { public string Description { get; private set; } public CustomDescriptionAttribute(string description) { Description = description; } } [CustomDescription("IProjectController")] public interface IProjectController { void Create(string projectName); } internal class ProjectController : IProjectController { public void Create(string projectName) { } } [TestFixture] public class CustomDescriptionAttributeTests { [Test] public void ProjectController_ShouldHaveCustomDescriptionAttribute() { Type type = typeof(ProjectController); object[] attributes = type.GetCustomAttributes( typeof(CustomDescriptionAttribute), true); // NUnit.Framework.AssertionException: Expected: 1 But was: 0 Assert.AreEqual(1, attributes.Length); } } 

Может ли class наследовать атрибуты из интерфейса? Или я лаяю здесь неправильное дерево?

Нет. При реализации интерфейса или переопределения членов в производном classе вам нужно повторно объявить атрибуты.

Если вы только заботитесь о ComponentModel (не прямое reflection), существует способ ( [AttributeProvider] ) предлагать атрибуты из существующего типа (во избежание дублирования), но он действителен только для использования свойств и индексатора.

В качестве примера:

 using System; using System.ComponentModel; class Foo { [AttributeProvider(typeof(IListSource))] public object Bar { get; set; } static void Main() { var bar = TypeDescriptor.GetProperties(typeof(Foo))["Bar"]; foreach (Attribute attrib in bar.Attributes) { Console.WriteLine(attrib); } } } 

выходы:

 System.SerializableAttribute System.ComponentModel.AttributeProviderAttribute System.ComponentModel.EditorAttribute System.Runtime.InteropServices.ComVisibleAttribute System.Runtime.InteropServices.ClassInterfaceAttribute System.ComponentModel.TypeConverterAttribute System.ComponentModel.MergablePropertyAttribute 

Вы можете определить полезный метод расширения …

 Type type = typeof(ProjectController); var attributes = type.GetCustomAttributes( true ); 

Вот способ расширения:

 /// Searches and returns attributes. The inheritance chain is not used to find the attributes. /// The type of attribute to search for. /// The type which is searched for the attributes. /// Returns all attributes. public static T[] GetCustomAttributes( this Type type ) where T : Attribute { return GetCustomAttributes( type, typeof( T ), false ).Select( arg => (T)arg ).ToArray(); } /// Searches and returns attributes. /// The type of attribute to search for. /// The type which is searched for the attributes. /// Specifies whether to search this member's inheritance chain to find the attributes. Interfaces will be searched, too. /// Returns all attributes. public static T[] GetCustomAttributes( this Type type, bool inherit ) where T : Attribute { return GetCustomAttributes( type, typeof( T ), inherit ).Select( arg => (T)arg ).ToArray(); } /// Private helper for searching attributes. /// The type which is searched for the attribute. /// The type of attribute to search for. /// Specifies whether to search this member's inheritance chain to find the attribute. Interfaces will be searched, too. /// An array that contains all the custom attributes, or an array with zero elements if no attributes are defined. private static object[] GetCustomAttributes( Type type, Type attributeType, bool inherit ) { if( !inherit ) { return type.GetCustomAttributes( attributeType, false ); } var attributeCollection = new Collection(); var baseType = type; do { baseType.GetCustomAttributes( attributeType, true ).Apply( attributeCollection.Add ); baseType = baseType.BaseType; } while( baseType != null ); foreach( var interfaceType in type.GetInterfaces() ) { GetCustomAttributes( interfaceType, attributeType, true ).Apply( attributeCollection.Add ); } var attributeArray = new object[attributeCollection.Count]; attributeCollection.CopyTo( attributeArray, 0 ); return attributeArray; } /// Applies a function to every element of the list. private static void Apply( this IEnumerable enumerable, Action function ) { foreach( var item in enumerable ) { function.Invoke( item ); } } 

Обновить:

Вот более короткая версия, предложенная SimonD в комментарии:

 private static IEnumerable GetCustomAttributesIncludingBaseInterfaces(this Type type) { var attributeType = typeof(T); return type.GetCustomAttributes(attributeType, true). Union(type.GetInterfaces(). SelectMany(interfaceType => interfaceType.GetCustomAttributes(attributeType, true))). Distinct().Cast(); } 

Статья Брэда Уилсона об этом: Атрибуты интерфейса! = Атрибуты classа

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

Если вам нужно наследовать атрибуты, используйте абстрактный базовый class, а не интерфейс.

Хотя class C # не наследует атрибуты от своих интерфейсов, есть полезная альтернатива при привязке моделей в ASP.NET MVC3.

Если вы объявляете модель представления как интерфейс, а не конкретный тип, тогда представление и привязка модели будут применять атрибуты (например, [Required] или [DisplayName("Foo")] из интерфейса при визуализации и проверке модель:

 public interface IModel { [Required] [DisplayName("Foo Bar")] string FooBar { get; set; } } public class Model : IModel { public string FooBar { get; set; } } 

Тогда в представлении:

 @* Note use of interface type for the view model *@ @model IModel @* This control will receive the attributes from the interface *@ @Html.EditorFor(m => m.FooBar) 

Это больше для людей, которые хотят извлечь атрибуты из свойств, которые могут существовать на реализованном интерфейсе. Поскольку эти атрибуты не являются частью classа, это даст вам доступ к ним. Заметьте, у меня есть простой class контейнера, который дает вам доступ к PropertyInfo – для этого я и нуждался. Взломайте, как вам нужно. Это сработало для меня.

 public static class CustomAttributeExtractorExtensions { ///  /// Extraction of property attributes as well as attributes on implemented interfaces. /// This will walk up recursive to collect any interface attribute as well as their parent interfaces. ///  ///  ///  ///  public static List> GetPropertyAttributesFromType(this Type typeToReflect) where TAttributeType : Attribute { var list = new List>(); // Loop over the direct property members var properties = typeToReflect.GetProperties(); foreach (var propertyInfo in properties) { // Get the attributes as well as from the inherited classes (true) var attributes = propertyInfo.GetCustomAttributes(true).ToList(); if (!attributes.Any()) continue; list.AddRange(attributes.Select(attr => new PropertyAttributeContainer(attr, propertyInfo))); } // Look at the type interface declarations and extract from that type. var interfaces = typeToReflect.GetInterfaces(); foreach (var @interface in interfaces) { list.AddRange(@interface.GetPropertyAttributesFromType()); } return list; } ///  /// Simple container for the Property and Attribute used. Handy if you want refrence to the original property. ///  ///  public class PropertyAttributeContainer { internal PropertyAttributeContainer(TAttributeType attribute, PropertyInfo property) { Property = property; Attribute = attribute; } public PropertyInfo Property { get; private set; } public TAttributeType Attribute { get; private set; } } } 
  • Как установить динамическое значение в моем атрибуте
  • Что такое начальный масштаб, пользовательский масштабируемый, минимальный масштаб, атрибут максимальной шкалы в метатеге?
  • Зацикливание объекта datetime приводит к числовому iteratorу
  • Как работают classы атрибутов?
  • Могут ли атрибуты добавляться динамически в C #?
  • Изменить параметр атрибута во время выполнения
  • Рекурсия, анализ XML-файла с атрибутами в treeview c #
  • Пользовательские ассемблеры сборки
  • В чем разница между использованием атрибута Serializable и внедрением ISerializable?
  • Атрибут InternalsVisibleTo не работает
  • Локализация DisplayNameAttribute
  • Давайте будем гением компьютера.