Avoid having different types with same name
Warns about multiple same-named types in different application or third-party namespaces or assemblies: confusion and naming collisions in source files using several of them.
How to fix
Rename concerned types.
CQLinq source
This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.
// <Name>Avoid having different types with same name</Name>
// <Id>ND2012:AvoidHavingDifferentTypesWithSameName</Id>
warnif count > 0
// Special type names for which multiple types
// with such name are allowed.
let nonReportedTypeName = new [] {
"Program", "NamespaceDoc", "Initial", "Startup",
"SwaggerConfig", "Constants", "MainWindow", "App", "Index",
"Create", "Read", "Update", "Delete", "Edit", "Details",
"View" }
// Special type name suffixes for which multiple types
// with such suffix are allowed.
let nonReportedTypeNameSuffix = new [] {
"Service", "Model", "Controller", "Page", "Pages" }
// This rule matches also collisions between
// application and third-party types sharing a same name.
let groups = JustMyCode.Types.Union(ThirdParty.Types)
// Discard nested types, whose name is
// prefixed with the parent type name.
.Where(t => !t.IsNested &&
!nonReportedTypeName.Contains(t.Name) &&
!t.Name.EndsWithAny(nonReportedTypeNameSuffix))
// Group types by name.
.GroupBy(t => t.Name)
from @group in groups
where @group.Count() > 1
// Let's see if types with the same name are declared
// in different namespaces.
// (t.FullName is {namespaceName}.{typeName} )
let groupsFullName = @group.GroupBy(t => t.FullName)
where groupsFullName.Count() > 1
// If several types with same name are declared in different
// namespaces eliminate the case where all types are declared
// in third-party assemblies.
let types = groupsFullName.SelectMany(g => g)
where types.Any(t => !t.IsThirdParty)
// Uncomment this line, to only gets naming collision involving
// both application and third-party types.
// && types.Any(t => t.IsThirdParty)
// Discard the group if at least two types are declared in
// the same source file(s): it means such files are shared
// amongst projects and it is not a problem.
let filePaths = types
.Where(t => t.SourceFileDeclAvailable)
.SelectMany(t => t.SourceDecls
.Select(d => d.SourceFile.FilePathString)
.Distinct(StringComparer.OrdinalIgnoreCase))
.ToArray()
where filePaths.Length == filePaths
.Distinct(StringComparer.OrdinalIgnoreCase).Count()
orderby types.Count() descending
// Don't match types containing extension methods
// whose name is less relevant
where !types.All(t => t.IsStatic &&
t.Methods.Any(m => m.IsExtensionMethod))
// Order types by parent namespace and assembly name, this way
// we always get the same type across sessions. Without this
// astute, the same issue would be seen as added/removed when
// the first type choosen in the group was not always the same,
// a situation that actually happens. Also make sure that the
// chosen type is not a third-party one.
let tMatched = types.OrderBy(t =>
(t.IsThirdParty ? "1" : "0") +
t.ParentNamespace.Name + t.ParentAssembly.Name).First()
select new {
t = tMatched,
// In the 'types' column, make sure to group matched types
// by parent assemblies and parent namespaces, to get a
// result more readable.
types,
namespaces = types.Except(tMatched)
.Select(t => t.ParentNamespace).Distinct(n => n.Name),
Debt = 10.ToMinutes().ToDebt(),
Severity = Severity.High
}
//<Expl>
// {2?A type:Several types} with the same name as the *{0}*
// {2?is:are} defined in the *{2}*.
// This leads to confusion and also naming collision.
//</Expl>
//<Desc>
// Warns about multiple same-named types in different
// *application* or *third-party* namespaces or assemblies:
// confusion and naming collisions in source files using
// several of them.
//</Desc>
//<HowToFix>
// Rename concerned types.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Naming Conventions: all 23 items
- Instance fields naming convention ND2000
- Static fields naming convention ND2001
- Interface name should begin with a 'I' ND2002
- Abstract base class should be suffixed with 'Base' ND2003
- Exception class name should be suffixed with 'Exception' ND2004
- Attribute class name should be suffixed with 'Attribute' ND2005
- Types name should begin with an Upper character ND2006
- Methods name should begin with an Upper character ND2007
- Do not name enum values 'Reserved' ND2008
- Avoid types with name too long ND2009
- Avoid methods with name too long ND2010
- Avoid fields with name too long ND2011
- Avoid having different types with same name ND2012
- Avoid prefixing type name with parent namespace name ND2013
- Avoid naming types and namespaces with the same identifier ND2014
- Don't call your method Dispose ND2015
- Methods prefixed with 'Try' should return a boolean ND2016
- Properties and fields that represent a collection of items should be named Items. ND2017
- DDD ubiquitous language check ND2018
- Avoid fields with same name in class hierarchy ND2019
- Avoid various capitalizations for method name ND2020
- Controller class name should be suffixed with 'Controller' ND2021
- Nested class members should not mask outer class' static members ND2022