Can a C# class inherit attributes from its interface?

This would appear to imply "no". Which is unfortunate.

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

Can a class inherit attributes from an interface? Or am I barking up the wrong tree here?

76765 次浏览

No. Whenever implementing an interface or overriding members in a derived class, you need to re-declare the attributes.

If you only care about ComponentModel (not direct reflection), there is a way ([AttributeProvider]) of suggesting attributes from an existing type (to avoid duplication), but it is only valid for property and indexer usage.

As an example:

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

outputs:

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

You can define a useful extension method ...

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

Here is the extension method:

/// <summary>Searches and returns attributes. The inheritance chain is not used to find the attributes.</summary>
/// <typeparam name="T">The type of attribute to search for.</typeparam>
/// <param name="type">The type which is searched for the attributes.</param>
/// <returns>Returns all attributes.</returns>
public static T[] GetCustomAttributes<T>( this Type type ) where T : Attribute
{
return GetCustomAttributes( type, typeof( T ), false ).Select( arg => (T)arg ).ToArray();
}


/// <summary>Searches and returns attributes.</summary>
/// <typeparam name="T">The type of attribute to search for.</typeparam>
/// <param name="type">The type which is searched for the attributes.</param>
/// <param name="inherit">Specifies whether to search this member's inheritance chain to find the attributes. Interfaces will be searched, too.</param>
/// <returns>Returns all attributes.</returns>
public static T[] GetCustomAttributes<T>( this Type type, bool inherit ) where T : Attribute
{
return GetCustomAttributes( type, typeof( T ), inherit ).Select( arg => (T)arg ).ToArray();
}


/// <summary>Private helper for searching attributes.</summary>
/// <param name="type">The type which is searched for the attribute.</param>
/// <param name="attributeType">The type of attribute to search for.</param>
/// <param name="inherit">Specifies whether to search this member's inheritance chain to find the attribute. Interfaces will be searched, too.</param>
/// <returns>An array that contains all the custom attributes, or an array with zero elements if no attributes are defined.</returns>
private static object[] GetCustomAttributes( Type type, Type attributeType, bool inherit )
{
if( !inherit )
{
return type.GetCustomAttributes( attributeType, false );
}


var attributeCollection = new Collection<object>();
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;
}


/// <summary>Applies a function to every element of the list.</summary>
private static void Apply<T>( this IEnumerable<T> enumerable, Action<T> function )
{
foreach( var item in enumerable )
{
function.Invoke( item );
}
}

Update:

Here is a shorter version as proposed by SimonD in a comment:

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

An article by Brad Wilson about this: Interface Attributes != Class Attributes

To summarise: classes don't inherit from interfaces, they implement them. This means that the attributes are not automatically part of the implementation.

If you need to inherit attributes, use an abstract base class, rather than an interface.

While a C# class does not inherit attributes from its interfaces, there is a useful alternative when binding models in ASP.NET MVC3.

If you declare the view's model to be the interface rather than the concrete type, then the view and the model binder will apply the attributes (e.g., [Required] or [DisplayName("Foo")] from the interface when rendering and validating the model:

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


public class Model : IModel {
public string FooBar { get; set; }
}

Then in the view:

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

This is more for people looking to extract attributes from properties that may exist on an implemented interface. Because those attributes are not part of the class, this will give you access to them. note, I have a simple container class that gives you access to the PropertyInfo - as that is what I needed it for. Hack up as you need. This worked well for me.

public static class CustomAttributeExtractorExtensions
{
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="TAttributeType"></typeparam>
/// <param name="typeToReflect"></param>
/// <returns></returns>
public static List<PropertyAttributeContainer<TAttributeType>> GetPropertyAttributesFromType<TAttributeType>(this Type typeToReflect)
where TAttributeType : Attribute
{
var list = new List<PropertyAttributeContainer<TAttributeType>>();


// 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<TAttributeType>(true).ToList();
if (!attributes.Any()) continue;


list.AddRange(attributes.Select(attr => new PropertyAttributeContainer<TAttributeType>(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<TAttributeType>());
}


return list;


}


/// <summary>
/// Simple container for the Property and Attribute used. Handy if you want refrence to the original property.
/// </summary>
/// <typeparam name="TAttributeType"></typeparam>
public class PropertyAttributeContainer<TAttributeType>
{
internal PropertyAttributeContainer(TAttributeType attribute, PropertyInfo property)
{
Property = property;
Attribute = attribute;
}


public PropertyInfo Property { get; private set; }


public TAttributeType Attribute { get; private set; }
}
}

EDIT: this covers inheriting attributes from interfaces on members (incl. properties). There are simple answers above for type definitions. I just posted this because I found it to be an irritating limitation and wanted to share a solution :)

Interfaces are multiple inheritance and behave as inheritance in the type system. There isn't a good reason for this kind of stuff. Reflection is a bit hokey. I've added comments to explain the nonsense.

(This is .NET 3.5 because this it just happens to be what the project I'm doing at the moment is using.)

// in later .NETs, you can cache reflection extensions using a static generic class and
// a ConcurrentDictionary. E.g.
//public static class Attributes<T> where T : Attribute
//{
//    private static readonly ConcurrentDictionary<MemberInfo, IReadOnlyCollection<T>> _cache =
//        new ConcurrentDictionary<MemberInfo, IReadOnlyCollection<T>>();
//
//    public static IReadOnlyCollection<T> Get(MemberInfo member)
//    {
//        return _cache.GetOrAdd(member, GetImpl, Enumerable.Empty<T>().ToArray());
//    }
//    //GetImpl as per code below except that recursive steps re-enter via the cache
//}


public static List<T> GetAttributes<T>(this MemberInfo member) where T : Attribute
{
// determine whether to inherit based on the AttributeUsage
// you could add a bool parameter if you like but I think it defeats the purpose of the usage
var usage = typeof(T).GetCustomAttributes(typeof(AttributeUsageAttribute), true)
.Cast<AttributeUsageAttribute>()
.FirstOrDefault();
var inherit = usage != null && usage.Inherited;


return (
inherit
? GetAttributesRecurse<T>(member)
: member.GetCustomAttributes(typeof (T), false).Cast<T>()
)
.Distinct()  // interfaces mean duplicates are a thing
// note: attribute equivalence needs to be overridden. The default is not great.
.ToList();
}


private static IEnumerable<T> GetAttributesRecurse<T>(MemberInfo member) where T : Attribute
{
// must use Attribute.GetCustomAttribute rather than MemberInfo.GetCustomAttribute as the latter
// won't retrieve inherited attributes from base *classes*
foreach (T attribute in Attribute.GetCustomAttributes(member, typeof (T), true))
yield return attribute;


// The most reliable target in the interface map is the property get method.
// If you have set-only properties, you'll need to handle that case. I generally just ignore that
// case because it doesn't make sense to me.
PropertyInfo property;
var target = (property = member as PropertyInfo) != null ? property.GetGetMethod() : member;


foreach (var @interface in member.DeclaringType.GetInterfaces())
{
// The interface map is two aligned arrays; TargetMethods and InterfaceMethods.
var map = member.DeclaringType.GetInterfaceMap(@interface);
var memberIndex = Array.IndexOf(map.TargetMethods, target); // see target above
if (memberIndex < 0) continue;


// To recurse, we still need to hit the property on the parent interface.
// Why don't we just use the get method from the start? Because GetCustomAttributes won't work.
var interfaceMethod = property != null
// name of property get method is get_<property name>
// so name of parent property is substring(4) of that - this is reliable IME
? @interface.GetProperty(map.InterfaceMethods[memberIndex].Name.Substring(4))
: (MemberInfo) map.InterfaceMethods[memberIndex];


// Continuation is the word to google if you don't understand this
foreach (var attribute in interfaceMethod.GetAttributes<T>())
yield return attribute;
}
}

Barebones NUnit test

[TestFixture]
public class GetAttributesTest
{
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
private sealed class A : Attribute
{
// default equality for Attributes is apparently semantic
public override bool Equals(object obj)
{
return ReferenceEquals(this, obj);
}


public override int GetHashCode()
{
return base.GetHashCode();
}
}


[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
private sealed class ANotInherited : Attribute { }


public interface Top
{
[A, ANotInherited]
void M();


[A, ANotInherited]
int P { get; }
}


public interface Middle : Top { }


private abstract class Base
{
[A, ANotInherited]
public abstract void M();


[A, ANotInherited]
public abstract int P { get; }
}


private class Bottom : Base, Middle
{
[A, ANotInherited]
public override void M()
{
throw new NotImplementedException();
}


[A, ANotInherited]
public override int P { get { return 42; } }
}


[Test]
public void GetsAllInheritedAttributesOnMethods()
{
var attributes = typeof (Bottom).GetMethod("M").GetAttributes<A>();
attributes.Should()
.HaveCount(3, "there are 3 inherited copies in the class heirarchy and A is inherited");
}


[Test]
public void DoesntGetNonInheritedAttributesOnMethods()
{
var attributes = typeof (Bottom).GetMethod("M").GetAttributes<ANotInherited>();
attributes.Should()
.HaveCount(1, "it shouldn't get copies of the attribute from base classes for a non-inherited attribute");
}


[Test]
public void GetsAllInheritedAttributesOnProperties()
{
var attributes = typeof(Bottom).GetProperty("P").GetAttributes<A>();
attributes.Should()
.HaveCount(3, "there are 3 inherited copies in the class heirarchy and A is inherited");
}


[Test]
public void DoesntGetNonInheritedAttributesOnProperties()
{
var attributes = typeof(Bottom).GetProperty("P").GetAttributes<ANotInherited>();
attributes.Should()
.HaveCount(1, "it shouldn't get copies of the attribute from base classes for a non-inherited attribute");
}
}

Add interface with properties that have attributes/custom attributes attached to the same properties that class have. We can extract the interface of the class by using Visual studio refactor feature. Have a partial class implement that interface.

Now Get "Type" object of the class object and get custom attributes from the property info using getProperties on Type object. This will not give the custom attributes on the class object as the class properties did not had the interface properties' custom attributes attached/inherited.

Now call GetInterface(NameOfImplemetedInterfaceByclass) on the class's Type object retrieved above. This will provide the interface's "Type" object. we should know the implemented interface's NAME. From Type object get property information and if the interface's property has any custom attributes attached then property information will provide custom attribute list. The implementing class must have provided implementation of the interface's properties. Match the class object's specific property name within the list of the interface's property information to get the custom attributes list.

This will work.

Though my answer is late and specific to a certain case, I would like to add some ideas. As suggested in other answers, Reflection or other methods would do it.

In my case a property (timestamp) was needed in all models to meet certain requirement (concurrency check attribute) in a Entity framework core project. We could either add [] above all class properties (adding in IModel interface which models implemented, didn't work). But I saved time through Fluent API which is helpful in these cases. In fluent API, I can check for specific property name in all models and set as IsConcurrencyToken() in 1 line !!

var props = from e in modelBuilder.Model.GetEntityTypes()
from p in e.GetProperties()
select p;
props.Where(p => p.PropertyInfo.Name == "ModifiedTime").ToList().ForEach(p => { p.IsConcurrencyToken = true; });

Likewise if you need any attribute to be added to same property name in 100's of classes/models, we can use fluent api methods for inbuilt or custom attribute resolver. Though EF (both core and EF6) fluent api may use reflection behind the scenes, we can save effort :)

One of the answers worked for attributes placed on the interface itself, but I was looking for interface property member attributes. I could not find it anywhere and had to alter some of the answers here to get what I needed. Going to leave the extension method I used here. This method will get all custom attributes of type T from a PropertyInfo including attributes placed on interfaces.

    public static IEnumerable<T> GetAllCustomAttributes<T> (this MemberInfo member) where T: Attribute
{
return member.GetCustomAttributes<T>(true)
.Union(member.DeclaringType.GetInterfaces().SelectMany(i => i.GetProperties())
.Select(p => p.GetCustomAttribute<T>(true)));
}

For my case I have a lot of cards and each card can have a two icons, but those icons refer to different values. All the values were being defined on my interfaces and I didn't want to bring each down to the class implementation since it would be the same across all cards. My usage looks like:

public interface IConsumable
{
[CardIcon(CardIconPosition.Right)]
public int Food { get; }
}
public class FoodCard : IConsumable
{
public bool TryGetCardIcon(CardIconPosition cardIconPosition, out string text)
{
var property = Card.GetType().GetProperties()
.FirstOrDefault(p => p.GetAllCustomAttributes<CardIconAttribute>()?
.Any(c => c.CardIconPosition == cardIconPosition) ?? false);


bool hasProperty = property != null;
text = string.Empty;


if (hasProperty)
{
text = property?.GetValue(Card).ToString() ?? string.Empty;
}


return hasProperty;
}
}