CA1501: Avoid excessive inheritance
Property | Value |
---|---|
Rule ID | CA1501 |
Title | Avoid excessive inheritance |
Category | Maintainability |
Fix is breaking or non-breaking | Breaking |
Default threshold | 5 |
Enabled by default in .NET 9 | No |
Cause
A type is five or more levels deep in its inheritance hierarchy.
Rule description
Deeply nested type hierarchies can be difficult to follow, understand, and maintain. This rule limits analysis to hierarchies in the same module.
You can configure this rule in the following ways:
- By default, the rule excludes types from the
System
namespace. You can configure the rule to exclude other types or namespaces as well. - You can configure the inheritance tree depth at which this rule fires.
How to fix violations
To fix a violation of this rule, derive the type from a base type that is less deep in the inheritance hierarchy or eliminate some of the intermediate base types.
When to suppress warnings
It's safe to suppress a warning from this rule. However, the code might be more difficult to maintain. Depending on the visibility of base types, resolving violations of this rule might create breaking changes. For example, removing public base types is a breaking change.
Note
You might see false positive warnings from this rule if all of the following apply:
- You're using Visual Studio 2022 version 17.5 or later with an older version of the .NET SDK, that is, .NET 6 or earlier.
- You're using the analyzers from the .NET 6 SDK or an older version of the analyzer packages, such as Microsoft.CodeAnalysis.FxCopAnalyzers.
The false positives are due to a breaking change in the C# compiler. Consider using a newer analyzer that contains the fix for the false positive warnings. Upgrade to Microsoft.CodeAnalysis.NetAnalyzers version 7.0.0-preview1.22464.1 or newer or use the analyzers from the .NET 7 SDK.
Suppress a warning
If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
#pragma warning disable CA1501
// The code that's violating the rule is on this line.
#pragma warning restore CA1501
To disable the rule for a file, folder, or project, set its severity to none
in the configuration file.
[*.{cs,vb}]
dotnet_diagnostic.CA1501.severity = none
For more information, see How to suppress code analysis warnings.
Configure threshold
You can configure the threshold at which this rule fires.
Create a text file named CodeMetricsConfig.txt.
Add the desired threshold to the text file in the following format:
CA1501: 8
In this example, the rule is configured to fire when a type is eight or more levels deep in its inheritance hierarchy.
In the project file, mark the build action of the configuration file as AdditionalFiles. For example:
<ItemGroup> <AdditionalFiles Include="CodeMetricsConfig.txt" /> </ItemGroup>
Configure code to analyze
Use the following option to configure which parts of your codebase to run this rule on.
You can configure this option for just this rule, for all rules it applies to, or for all rules in this category (Maintainability) that it applies to. For more information, see Code quality rule configuration options.
Inheritance excluded type or namespace names
You can configure the rule to exclude certain types or namespaces from the inheritance hierarchy tree. By default, all types from the System.*
namespace are excluded. No matter what value you set, this default value is added.
Option Value | Summary |
---|---|
dotnet_code_quality.CA1501.additional_inheritance_excluded_symbol_names = MyType |
Matches all types named MyType or whose containing namespace contains MyType (and all types from the System namespace) |
dotnet_code_quality.CA1501.additional_inheritance_excluded_symbol_names = MyType1|MyType2 |
Matches all types named either MyType1 or MyType2 or whose containing namespace contains either MyType1 or MyType2 (and all types from the System namespace) |
dotnet_code_quality.CA1501.additional_inheritance_excluded_symbol_names = T:NS.MyType |
Matches specific type MyType in the namespace NS (and all types from the System namespace) |
dotnet_code_quality.CA1501.additional_inheritance_excluded_symbol_names = T:NS1.MyType1|T:NS2.MyType2 |
Matches specific types MyType1 and MyType2 with respective fully qualified names (and all types from the System namespace) |
dotnet_code_quality.CA1501.additional_inheritance_excluded_symbol_names = N:NS |
Matches all types from the NS namespace (and all types from the System namespace) |
dotnet_code_quality.CA1501.additional_inheritance_excluded_symbol_names = My* |
Matches all types whose name starts with My or whose containing namespace parts starts with My (and all types from the System namespace) |
dotnet_code_quality.CA1501.additional_inheritance_excluded_symbol_names = T:NS.My* |
Matches all types whose name starts with My in the namespace NS (and all types from the System namespace) |
dotnet_code_quality.CA1501.additional_inheritance_excluded_symbol_names = N:My* |
Matches all types whose containing namespace starts with My (and all types from the System namespace) |
Example
The following example shows a type that violates the rule:
class BaseClass {}
class FirstDerivedClass : BaseClass {}
class SecondDerivedClass : FirstDerivedClass {}
class ThirdDerivedClass : SecondDerivedClass {}
class FourthDerivedClass : ThirdDerivedClass {}
// This class violates the rule.
class FifthDerivedClass : FourthDerivedClass {}
Imports System
Namespace ca1501
Class BaseClass
End Class
Class FirstDerivedClass
Inherits BaseClass
End Class
Class SecondDerivedClass
Inherits FirstDerivedClass
End Class
Class ThirdDerivedClass
Inherits SecondDerivedClass
End Class
Class FourthDerivedClass
Inherits ThirdDerivedClass
End Class
' This class violates the rule.
Class FifthDerivedClass
Inherits FourthDerivedClass
End Class
End Namespace