C# AllowMultiple Attributes on Derived 类

C# AllowMultiple Attributes on Derived Classes

考虑下面的代码片段:

[AttributeUsage(AttributeTargets.Class, AllowMultiple =true)]
public class FooAttribute : Attribute {
    public string Bar { get; set; } 
}

[Foo(Bar = "A")]
public class A{}

[Foo(Bar = "B")]
public class B : A{}

[Foo(Bar = "C")]
public class C : B{}

如果我尝试获取 class 的 FooAttribute C

var attrList = typeof(C).GetCustomAttributes(typeof(FooAttribute), true) as FooAttribute[];

我会得到全部3个属性。而顺序是C,B,A。所以这是我的问题:

通常无法保证顺序,编译器会根据平台、文化和编译器版本产生不同的结果。然而,在这个特定场景中,保证顺序正确(至少部分正确)。例外情况是当您在同一继承级别分配多个属性时:

[AttributeUsage(AttributeTargets.Class, AllowMultiple =true)]
public class FooAttribute : Attribute {
    public string Bar { get; set; } 
}

[Foo(Bar = "A")]
public class A{}

[Foo(Bar = "B"), Foo(Bar = "C")]
public class B : A{}

A(最后)的顺序始终相同,但 B 和 C 可能会有所不同:C-B-A 或 B-C-一种。在以下示例中,根本无法保证顺序:

[Foo(Bar = "A"), Foo(Bar = "B"), Foo(Bar = "C")]
public class A{}

但是如果您将一个属性分配给每个继承级别,顺序将保持不变。这是由于 .NET (Framework) 中的实现,因为它遍历每个基本类型以收集所有属性(如果您 Type.GetCustomAttributes(Type, inherit: true))。这个可以看这段代码(System.Private.CoreLib,System.Reflection):

private static Attribute[] InternalGetCustomAttributes(EventInfo element, Type type, bool inherit)
{
    [...]

    // walk up the hierarchy chain
    Attribute[] attributes = (Attribute[])element.GetCustomAttributes(type, inherit);
    if (inherit)
    {
        // create the hashtable that keeps track of inherited types
        Dictionary<Type, AttributeUsageAttribute> types = new Dictionary<Type, AttributeUsageAttribute>(11);
        // create an array list to collect all the requested attibutes
        List<Attribute> attributeList = new List<Attribute>();
        CopyToArrayList(attributeList, attributes, types);

        EventInfo? baseEvent = GetParentDefinition(element);
        while (baseEvent != null)
        {
            attributes = GetCustomAttributes(baseEvent, type, false);
            AddAttributesToList(attributeList, attributes, types);
            baseEvent = GetParentDefinition(baseEvent);
        }
        Attribute[] array = CreateAttributeArrayHelper(type, attributeList.Count);
        attributeList.CopyTo(array, 0);
        return array;
    }
    else
        return attributes;
}

请注意,这适用于 events,但也适用于 MemberInfo (Type)。