Analyzers

April 10, 2026 ยท View on GitHub

windows build & test Nuget

Analyzers

This project provides several new C# code analysis rules for projects built with the .NET 10 SDK or later. These rules can be used with other analyzers like .NET's.

This software is CharityWare. If you use it, I ask that you donate something to the charity of your choice.

IDTitleComment
MEN001Tabs should be used for indentationEnsures tabs are used for indentation instead of spaces. This is the opposite of StyleCop's SA1027: TabsMustNotBeUsed rule. This is similar to the StyleCop+ rule SP2001: CheckAllowedIndentationCharacters when set to "Tabs only".

This rule is off by default because it conflicts with Visual Studio's default settings, which use spaces instead of tabs for indentation. This rule can be enabled using a custom ruleset file, and it includes a code fix provider.
MEN002Line is too longEnsures that lines are not longer than 160 characters. This is similar to the StyleCop+ rule SP2100: CodeLineMustNotBeLongerThan. The MaxLineColumns and TabSize values for this rule can be configured in .editorconfig.
MEN002ALine is longNotifies when lines are longer than 160 characters. This rule is off by default because MEN002 takes precedence and is sufficient for most cases. If you enable this rule, then you should also configure NotifyLineColumns to be less than MaxLineColumns in .editorconfig.
MEN003Method is too longEnsures that methods are not longer than 120 lines. This is similar to the StyleCop+ rule SP2101: MethodMustNotContainMoreLinesThan. The MaxMethodLines limit for this rule can be configured in .editorconfig.
MEN004Property accessor is too longEnsures that property accessors are not longer than 80 lines. This is similar to the StyleCop+ rule SP2102: PropertyMustNotContainMoreLinesThan. The MaxPropertyAccessorLines limit for this rule can be configured in .editorconfig.
MEN005File is too longEnsures that files are not longer than 2000 lines. This is similar to the StyleCop+ rule SP2103: FileMustNotContainMoreLinesThan. The MaxFileLines limit for this rule can be configured in .editorconfig.
MEN006#regions should be usedRecommends that #regions be used when there are over 100 lines in a file or if there is more than one class, struct, enum, or interface defined in a file.

This rule is off by default because it conflicts with StyleCop's SA1124: DoNotUseRegions rule. This rule can be enabled using a custom ruleset file. The MaxUnregionedLines limit for this rule can be configured in .editorconfig.

Note: Menees VS Tools can be used to easily add, collapse, and expand #regions in C# code (as well as in VB, XML, XAML, HTML, SQL, JavaScript, and TypeScript code).
MEN007Use a single returnRecommends that only a single return statement should be used in a code block. "One entry, one exit" keeps control flow simple and makes refactoring easier.
MEN008File name should match typeEnsures that a file name matches or includes the name of the main type it contains. The TypeFileNameExclusions for this rule can be configured in .editorconfig.
MEN009Use the preferred exception typeRecommends preferred exception types (e.g., NotSupportedException instead of NotImplementedException). This rule is a complement to CA2201, and it includes a code fix provider.
MEN010Avoid magic numbersRecommends that named constants be used instead of numeric literals (i.e., magic numbers). The AllowedNumericLiterals for this rule can be configured in .editorconfig.
MEN011Align using directivesEnsures that using directives are aligned. This is important when using directives are nested inside a namespace (per SA1200: UsingDirectivesMustBePlacedWithinNamespace) because Visual Studio will often fail to indent them correctly if they're added while code contains syntax errors. This rule includes a code fix provider.
MEN012Flags should be powers of twoFlags enum members should be powers of two or bitwise-or combinations of named members. This rule is a complement to CA2217.
MEN013Use UTC timeRecommends UTC times because they're unambiguous and always increasing. This rule includes a code fix provider.
MEN014Prefer TryGetValueRecommends calling TryGetValue (for a single lookup and retrieval) instead of ContainsKey and this[key] with duplicate lookups.
MEN015Use Preferred TermsSimilar to the old FxCop CA1726 rule except this rule only checks single terms (not double terms). So it uses a slightly different set of default preferred terms (omitting double terms like LogOn), and it includes Id as a preferred term over ID (per FxCop's CA1709 rule).
MEN016Avoid Top-Level StatementsC# top-level statements are only for toy/example programs and should be avoided in long-term code for consistency and maintainability.
MEN017Remove Unused Private SetterA private set accessor is not needed when an auto property is only assigned in the constructor. Inspired by C# Essentials' Use Getter-Only Auto-Property.
MEN018Use Digit SeparatorsNumeric literals should use digit separators ('_' from C# 7) to improve readability. This applies to hexadecimal, binary, and integer or real literals.
MEN019Async method needs CancellationTokenAn async method should take a CancellationToken parameter or take a parameter that has a public CancellationToken property. Inspired by this dotnet issue and related to CA2016 and CA1068.
MEN020BUse preferred var style for built-in typesLocal variable declarations for built-in types (e.g., int, string, bool) should use the preferred var style based on the configured BuiltInTypes rules. This rule includes a code fix provider and is related to IDE0007 and IDE0008.
MEN020SUse preferred var style for simple typesLocal variable declarations for simple types (non-generic, non-built-in types like Guid, MyClass) should use the preferred var style based on the configured SimpleTypes rules. This rule includes a code fix provider and is related to IDE0007 and IDE0008.
MEN020EUse preferred var style elsewhereLocal variable declarations for other types (e.g., generic types like List<int>, Dictionary<string, int>) should use the preferred var style based on the configured Elsewhere rules. This rule includes a code fix provider and is related to IDE0007 and IDE0008.

Configuration

Many of the rule limits and settings can be configured via .editorconfig.

.editorconfig

Add menees_analyzers.* keys to your .editorconfig file:

[*.cs]
menees_analyzers.max_line_columns = 120
menees_analyzers.tab_size = 4
menees_analyzers.allow_long_uri_lines = true
menees_analyzers.preferred_term.Cancelled = Canceled
menees_analyzers.var_style.built_in_types = use_explicit_type

Supported keys

CategoryKeyTypeDefault
Scalarsmenees_analyzers.tab_sizeint4
menees_analyzers.max_line_columnsint160
menees_analyzers.notify_line_columnsint160
menees_analyzers.max_method_linesint120
menees_analyzers.max_property_accessor_linesint80
menees_analyzers.max_file_linesint2000
menees_analyzers.max_unregioned_linesint100
menees_analyzers.allow_long_uri_linesbooltrue
menees_analyzers.allow_long_four_slash_comment_linesboolfalse
Cancellationmenees_analyzers.cancellation.check_private_methodsboolfalse
menees_analyzers.cancellation.check_private_typesboolfalse
menees_analyzers.cancellation.property_namescomma-delimitedCancellationToken, Cancellation
Digit Separatorsmenees_analyzers.decimal.min_sizebyte6
menees_analyzers.decimal.group_sizebyte3
menees_analyzers.hexadecimal.min_sizebyte8
menees_analyzers.hexadecimal.group_sizebyte4
menees_analyzers.binary.min_sizebyte8
menees_analyzers.binary.group_sizebyte4
Collectionsmenees_analyzers.allowed_numeric_literalscomma-delimited0, 1, 2, 100
menees_analyzers.allowed_numeric_caller_namescomma-delimitedFromDays, FromHours, ...
menees_analyzers.allowed_numeric_caller_regexescomma-delimited(none)
menees_analyzers.test_class_attributescomma-delimitedTestClass, TestFixture
menees_analyzers.test_method_attributescomma-delimitedTestMethod, Test, Fact, Theory
File Exclusionsmenees_analyzers.analyze_file_name_exclusionscomma-delimitedGeneratedCode.cs
menees_analyzers.analyze_file_regex_exclusionscomma-delimited(see source)
menees_analyzers.type_file_name_exclusionscomma-delimitedEnumerations.cs, Interfaces.cs, Delegates.cs
menees_analyzers.type_file_regex_exclusionscomma-delimited(see source)
Preferred Termsmenees_analyzers.preferred_term.<Avoid>string (Prefer)(merged with defaults)
Var Stylemenees_analyzers.var_style.built_in_typesuse_explicit_type | use_var(none)
menees_analyzers.var_style.simple_typesuse_explicit_type | use_var(none)
menees_analyzers.var_style.elsewhereuse_explicit_type | use_var(none)
Var Conditionsmenees_analyzers.var_style.<category>.foreachbool
menees_analyzers.var_style.<category>.linq_scalar_resultbool
menees_analyzers.var_style.<category>.linq_collection_resultbool
menees_analyzers.var_style.<category>.linq_aggregate_resultbool
menees_analyzers.var_style.<category>.long_type_namebool
menees_analyzers.var_style.<category>.long_type_name_lengthint30
menees_analyzers.var_style.<category>.evidentbool

Notes:

  • Comma-delimited collections (e.g., allowed_numeric_literals) replace the defaults entirely when specified.
  • Preferred terms merge with the defaults: .editorconfig terms add to or override the default preferred terms.
  • Var style conditions (foreach, evident, etc.) apply only when the mode is use_var. The <category> placeholder is built_in_types, simple_types, or elsewhere.

Migrating From XML Settings

In version 4.0, support for Menees.Analyzers.Settings.xml was removed. All settings must now be configured via .editorconfig. The following table maps each former XML setting (as an XPath expression) to its .editorconfig counterpart:

XML Setting (XPath).editorconfig Key
/Menees.Analyzers.Settings/TabSizemenees_analyzers.tab_size
/Menees.Analyzers.Settings/MaxLineColumnsmenees_analyzers.max_line_columns
/Menees.Analyzers.Settings/NotifyLineColumnsmenees_analyzers.notify_line_columns
/Menees.Analyzers.Settings/MaxMethodLinesmenees_analyzers.max_method_lines
/Menees.Analyzers.Settings/MaxPropertyAccessorLinesmenees_analyzers.max_property_accessor_lines
/Menees.Analyzers.Settings/MaxFileLinesmenees_analyzers.max_file_lines
/Menees.Analyzers.Settings/MaxUnregionedLinesmenees_analyzers.max_unregioned_lines
/Menees.Analyzers.Settings/AllowLongUriLinesmenees_analyzers.allow_long_uri_lines
/Menees.Analyzers.Settings/AllowLongFourSlashCommentLinesmenees_analyzers.allow_long_four_slash_comment_lines
/Menees.Analyzers.Settings/AnalyzeFileNameExclusions/FileNamemenees_analyzers.analyze_file_name_exclusions (comma-delimited)
/Menees.Analyzers.Settings/AnalyzeFileNameExclusions/FileRegexmenees_analyzers.analyze_file_regex_exclusions (comma-delimited)
/Menees.Analyzers.Settings/TypeFileNameExclusions/FileNamemenees_analyzers.type_file_name_exclusions (comma-delimited)
/Menees.Analyzers.Settings/TypeFileNameExclusions/FileRegexmenees_analyzers.type_file_regex_exclusions (comma-delimited)
/Menees.Analyzers.Settings/AllowedNumericLiterals/Literalmenees_analyzers.allowed_numeric_literals (comma-delimited)
/Menees.Analyzers.Settings/AllowedNumericLiterals/CallerNamemenees_analyzers.allowed_numeric_caller_names (comma-delimited)
/Menees.Analyzers.Settings/AllowedNumericLiterals/CallerRegexmenees_analyzers.allowed_numeric_caller_regexes (comma-delimited)
/Menees.Analyzers.Settings/UnitTestAttributes/Classmenees_analyzers.test_class_attributes (comma-delimited)
/Menees.Analyzers.Settings/UnitTestAttributes/Methodmenees_analyzers.test_method_attributes (comma-delimited)
/Menees.Analyzers.Settings/PreferredTerms/Term[@Avoid]menees_analyzers.preferred_term.<Avoid> = <Prefer>
/Menees.Analyzers.Settings/DigitSeparators/Decimal/@MinSizemenees_analyzers.decimal.min_size
/Menees.Analyzers.Settings/DigitSeparators/Decimal/@GroupSizemenees_analyzers.decimal.group_size
/Menees.Analyzers.Settings/DigitSeparators/Hexadecimal/@MinSizemenees_analyzers.hexadecimal.min_size
/Menees.Analyzers.Settings/DigitSeparators/Hexadecimal/@GroupSizemenees_analyzers.hexadecimal.group_size
/Menees.Analyzers.Settings/DigitSeparators/Binary/@MinSizemenees_analyzers.binary.min_size
/Menees.Analyzers.Settings/DigitSeparators/Binary/@GroupSizemenees_analyzers.binary.group_size
/Menees.Analyzers.Settings/SupportAsyncCancellationToken/@CheckPrivateMethodsmenees_analyzers.cancellation.check_private_methods
/Menees.Analyzers.Settings/SupportAsyncCancellationToken/@CheckPrivateTypesmenees_analyzers.cancellation.check_private_types
/Menees.Analyzers.Settings/SupportAsyncCancellationToken/Properties/Propertymenees_analyzers.cancellation.property_names (comma-delimited)
/Menees.Analyzers.Settings/UsePreferredVarStyle/BuiltInTypesmenees_analyzers.var_style.built_in_types
/Menees.Analyzers.Settings/UsePreferredVarStyle/SimpleTypesmenees_analyzers.var_style.simple_types
/Menees.Analyzers.Settings/UsePreferredVarStyle/Elsewheremenees_analyzers.var_style.elsewhere
UseVar/Foreachmenees_analyzers.var_style.<category>.foreach
UseVar/LinqScalarResultmenees_analyzers.var_style.<category>.linq_scalar_result
UseVar/LinqCollectionResultmenees_analyzers.var_style.<category>.linq_collection_result
UseVar/LinqAggregateResultmenees_analyzers.var_style.<category>.linq_aggregate_result
UseVar/LongTypeNamemenees_analyzers.var_style.<category>.long_type_name
UseVar/LongTypeName/@Lengthmenees_analyzers.var_style.<category>.long_type_name_length
UseVar/Evidentmenees_analyzers.var_style.<category>.evident