Type name uses a reserved suffix its declaration does not earn
ID |
vbnet.maintainability.identifiers_no_incorrect_suffix |
Severity |
info |
Remediation Complexity |
medium |
Remediation Risk |
medium |
Remediation Effort |
low |
Resource |
Naming |
Language |
VB.NET |
Description
Reports a Class or Structure whose name ends in one of the suffixes .NET reserves for a specific kind of type - Exception, Attribute, EventArgs, EventHandler, Collection, Dictionary, Stream or Permission - while the declaration has no Inherits clause and no Implements clause at all, so nothing in it supports the claim the name makes. ValidationException that derives from nothing, AuditAttribute that is a plain class and OrderCollection that merely holds a List(Of T) are all reported. This is the counterpart of the rules that report a type deriving from a base while lacking the matching suffix: a declaration is reported by one of them or by this one, never by both. This is a convention rule and is reported at informational severity.
Rationale
These suffixes are read as type information rather than as words. A developer who sees ValidationException in a signature concludes it can be thrown and caught, and will write Catch ex As ValidationException; if the type does not derive from Exception that code does not compile, and the developer has to go and read the declaration to find out why. AuditAttribute is worse, because it will be reached for as <Audit> on a declaration, which fails for a reason the error message states only obliquely. OrderCollection will be passed where a sequence is expected and enumerated in a For Each, neither of which works. In each case the name has made a promise the type cannot keep, and the cost is paid by every developer who believes it - one compile error and one trip to the declaration each, repeated for as long as the name survives. The suffix also blocks the name for the type that should have had it: once OrderCollection is a plain wrapper, the real collection has to be called something else, and the namespace ends up with two similarly named types whose difference is not visible from their names.
The following code illustrates the pattern detected by this rule:
Namespace Ordering
' BAD: named as an exception but derives from nothing.
' FLAGGED: Type name uses a reserved suffix its declaration does not earn
Public Class ValidationException
Public Property Reason As String
End Class
Remediation
Decide which of the two the name got wrong. If the type is meant to be what the suffix says, make the declaration say so: derive from Exception and add the standard constructors, derive from Attribute and add an <AttributeUsage>, derive from EventArgs, or implement ICollection or IDictionary - or derive from Collection(Of T), which supplies the whole contract for you. If the type is not that kind of thing, drop the suffix and name it for what it actually is: ValidationException holding a reason becomes ValidationResult or ValidationFailure, AuditAttribute becomes AuditRecord or AuditEntry, OrderCollection wrapping a list becomes OrderBook, OrderSet only if it really behaves as a set, or simply expose the list as a property of Order. Renaming is usually the cheaper of the two and is the right answer when the type has no need for the contract; use the rename refactoring in the IDE so that every signature and instantiation is updated in the same step.