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 8 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:

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.

  1. Create a text file named CodeMetricsConfig.txt.

  2. 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.

  3. 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