¿Puede una clase C # heredar atributos de su interfaz?

Esto parece implicar “no”. Lo cual es desafortunado

[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); } } 

¿Puede una clase heredar atributos de una interfaz? ¿O estoy ladrando el árbol equivocado aquí?

No. Cuando se implementa una interfaz o se anulan miembros en una clase derivada, debe volver a declarar los atributos.

Si solo se preocupa por ComponentModel (no reflection directo), hay una forma ( [AttributeProvider] ) de sugerir atributos de un tipo existente (para evitar la duplicación), pero solo es válido para el uso de la propiedad y el indexador.

Como ejemplo:

 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); } } } 

productos:

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

Puede definir un método de extensión útil …

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

Aquí está el método de extensión:

 /// 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 ); } } 

Actualizar:

Aquí hay una versión más corta propuesta por SimonD en un comentario:

 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(); } 

Un artículo de Brad Wilson sobre esto: ¡Atributos de la interfaz! = Atributos de la clase

Para resumir: las clases no heredan de las interfaces, las implementan. Esto significa que los atributos no son automáticamente parte de la implementación.

Si necesita heredar atributos, use una clase base abstracta, en lugar de una interfaz.

Si bien una clase C # no hereda los atributos de sus interfaces, existe una alternativa útil al vincular modelos en ASP.NET MVC3.

Si declara que el modelo de la vista es la interfaz en lugar del tipo concreto, la vista y el encuadernador del modelo aplicarán los atributos (por ejemplo, [Required] o [DisplayName("Foo")] de la interfaz al representar y validar el modelo:

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

Luego en la vista:

 @* 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) 

Esto es más para las personas que buscan extraer atributos de las propiedades que pueden existir en una interfaz implementada. Debido a que esos atributos no son parte de la clase, esto le dará acceso a ellos. tenga en cuenta que tengo una clase de contenedor simple que le da acceso a PropertyInfo, ya que eso es para lo que lo necesitaba. Hack up como lo necesites. Esto funcionó bien para mí.

 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; } } }