Avoid defining multiple types in a source file
Multiple types in one source file decrease readability (developers expect one type per file in the Solution Explorer) and lead to files with too many lines. Each match is such a source file, indexed by one of its types (preferably the one named like the file).
Nested types, enumerations and file-visibility types are exempt: it is acceptable to declare them alongside their principal user type.
Nested types, enumerations and file-visibility types are exempt: it is acceptable to declare them alongside their principal user type.
How to fix
Create a source file per type. Severity is Low: more an advice than a problem.
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 defining multiple types in a source file</Name>
// <Id>ND2102:AvoidDefiningMultipleTypesInASourceFile</Id>
warnif count > 0
// Build a lookup indexed by source files, values being a sequence of types defined in the source file.
let lookup = JustMyCode.Types
// When a source file is referenced by several assemblies,
// type(s) contained in the source file are seen as distinct types, both by the CLR and by NDepend.
// This Distinct clause based on type full-name (type name prefixed with namespace)
// avoids matching the multiple versions of such type.
.Distinct(t => t.FullName)
.Where(t => t.SourceFileDeclAvailable &&
// except enumerations, nested types and types generated by compilers!
!t.IsEnumeration &&
!t.IsNested &&
!t.IsGeneratedByCompiler &&
// Allow to have multiple 'file' types in the same source file
!t.IsVisibleOnlyInFile)
// We use multi-key, since a type can be declared in multiple source files.
.ToMultiKeyLookup(t => t.SourceDecls.Select(d => d.SourceFile))
from @group in lookup where @group.Count() > 1
let sourceFile = @group.Key
// CQLinq doesn't let indexing result with sourceFile
// so we choose a typeIndex in types,
// preferably the type that has the file name.
let typeWithSourceFileName = @group.FirstOrDefault(t => t.SimpleNameEquals(sourceFile.FileNameWithoutExtension))
let typeIndex = typeWithSourceFileName ?? @group.First()
// Don't warn for types with at least one declaration in a generated file
// like the UWP generated file 'App.g.i.cs'
where sourceFile.FilePathString.IndexOf(".g.", StringComparison.OrdinalIgnoreCase) == -1
select new {
typeIndex,
TypesInSourceFile = @group as IEnumerable<IType>,
SourceFilePathString = sourceFile.FilePathString,
SourceFileNameString = sourceFile.FileName,
Debt = 3.ToMinutes().ToDebt(),
Severity = Severity.Low
}
//<Expl>The source file *{3}* should contain only one type declaration instead of *{1}*.</Expl>
//<Desc>
// Multiple types in one source file decrease readability (developers expect
// one type per file in the *Solution Explorer*) and lead to files with too
// many lines. Each match is such a source file, indexed by one of its types
// (preferably the one named like the file).
//
// Nested types, enumerations and *file*-visibility types are exempt: it is
// acceptable to declare them alongside their principal user type.
//</Desc>
//<HowToFix>
// Create a source file per type. Severity is **Low**: more an advice than a
// problem.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Source Files Organization: all 6 items
- Avoid referencing source file out of the project directory ND2100
- Avoid duplicating a type definition across assemblies ND2101
- Avoid defining multiple types in a source file ND2102
- Namespace name should correspond to file location ND2103
- Types with source files stored in the same directory, should be declared in the same namespace ND2104
- Types declared in the same namespace, should have their source files stored in the same directory ND2105