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。所以这是我的问题:
- 此顺序是否为保证行为,这意味着派生 class 的属性总是出现在比其基础 class 更小的索引处?
- 是否可以知道该属性属于哪个具体类型?
通常无法保证顺序,编译器会根据平台、文化和编译器版本产生不同的结果。然而,在这个特定场景中,保证顺序正确(至少部分正确)。例外情况是当您在同一继承级别分配多个属性时:
[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
)。
考虑下面的代码片段:
[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。所以这是我的问题:
- 此顺序是否为保证行为,这意味着派生 class 的属性总是出现在比其基础 class 更小的索引处?
- 是否可以知道该属性属于哪个具体类型?
通常无法保证顺序,编译器会根据平台、文化和编译器版本产生不同的结果。然而,在这个特定场景中,保证顺序正确(至少部分正确)。例外情况是当您在同一继承级别分配多个属性时:
[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
)。