Avoid Unsealed Attributes
ID |
csharp.avoid_unsealed_attributes |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Efficiency |
Language |
CSharp |
Tags |
attributes, efficiency, performance |
Description
Reports custom Attribute classes declared without the sealed modifier. The CLR’s
attribute-reflection paths are significantly faster when the attribute type is
sealed because they can skip the inheritance walk.
Rationale
The .NET design guidelines explicitly recommend sealing attribute classes. Every
attribute in the base class library is sealed (SerializableAttribute,
ObsoleteAttribute, FlagsAttribute, …). Leaving an attribute open for
inheritance pays a reflection cost on every lookup and almost never reflects an
intentional extensibility point.
public class MyAttribute : Attribute { } // FLAW
public sealed class MyOtherAttribute : Attribute { } // OK
The check is conservative about what counts as an attribute class. A class derives
from Attribute when its base is Attribute/System.Attribute, or when a base class
declared in the same file transitively reaches it. A base class name that merely ends
with Attribute but is declared elsewhere (or not at all in this file) is not enough on
its own — Attribute is also a common domain term (e.g. a product or customer attribute
entity such as Color or Size), so an unresolved base is left unreported rather than
guessed at:
|
public abstract class BaseAttribute : BaseEntity { } // domain entity, not System.Attribute
public class AddressAttribute : BaseAttribute { } // OK, base chain doesn't reach Attribute
Remediation
Add the sealed modifier to the class header. If the attribute is genuinely
intended as a base for further attributes, mark it abstract instead and document
the extensibility point.