Interface name does not start with an I prefix
ID |
vbnet.maintainability.interface_first_letter |
Severity |
info |
Remediation Complexity |
trivial |
Remediation Risk |
medium |
Remediation Effort |
low |
Resource |
Naming |
Language |
VB.NET |
Description
Reports an Interface declaration whose name is PascalCase but does not begin with the I prefix, that is a capital I immediately followed by another capital letter - Shipper instead of IShipper, Repository(Of TEntity) instead of IRepository(Of TEntity). A name such as Identity is also reported: its I is the first letter of a word rather than the prefix, so the interface should be IIdentity. Generic interfaces are judged on their own name and not on their type parameters. Names that are not PascalCase at all are left to the general type naming rule, so a declaration is reported by one rule or the other and never by both. This is a convention rule and is reported at informational severity.
Rationale
The I prefix is the one place .NET breaks its own "no Hungarian notation" guideline, and it does so on purpose: interfaces and classes occupy the same namespace and appear in exactly the same positions in source - a parameter type, a return type, an Implements clause, a generic constraint - and whether a type is an interface changes what a developer may do with it. You cannot instantiate it, it carries no state, a class may implement several of them, and a parameter typed on one is a seam you can substitute in a test. Without the prefix none of that is visible at the point of use: Function Load(ByVal source As Shipper) gives no hint that a test double can be passed, while As IShipper says so immediately. The prefix also resolves the commonest naming collision in .NET design, an interface and its default implementation that want the same name - IShipper and Shipper coexist, whereas Shipper and ShipperImpl force a Java idiom onto the codebase. Because interface names appear in every implementing class and every consumer signature, renaming later is a wide change; renaming at declaration time is one refactoring.
The following code illustrates the pattern detected by this rule:
Namespace Shipping
' BAD: an interface name must begin with I followed by a capital letter.
' FLAGGED: Interface name does not start with an I prefix
Public Interface Shipper
Sub Ship(ByVal sku As String)
End Interface
' BAD: the I here is the first letter of a word, not the interface prefix.
' FLAGGED: Interface name does not start with an I prefix
Public Interface Identity
ReadOnly Property Name As String
End Interface
' BAD: a generic interface follows the same convention.
' FLAGGED: Interface name does not start with an I prefix
Public Interface Repository(Of TEntity)
Sub Add(ByVal entity As TEntity)
End Interface
' GOOD: I plus a PascalCase name.
Remediation
Rename the interface to a capital I followed by a PascalCase name: Shipper becomes IShipper, Repository(Of TEntity) becomes IRepository(Of TEntity), and Identity becomes IIdentity - the doubled I is correct and is what the framework itself does, as in IIdentity, IInterfaceInfo and IImageEncoder. Keep the letter after the prefix upper case, including for acronyms, so IOStream reads as the prefix plus OStream rather than as the IO acronym; if that ambiguity matters, prefer a name whose first word is unmistakable. If a class and its interface currently share a stem, take the chance to give the interface the prefix and leave the class its plain name rather than adding an Impl or Base suffix. Use the rename refactoring in the IDE so that every Implements clause, signature and generic constraint is updated in the same step; for an interface that is already published, keep the old name only if external consumers depend on it, and mark it <Obsolete>.