A Roslyn analyzer to enforce some good practices in C# in terms of design, usage, security, performance, and style.
Install the NuGet package https://www.nuget.org/packages/Meziantou.Analyzer/
If you are already using other analyzers, you can check which rules are duplicated with well-known analyzers
| Id | Category | Description | Severity | Is enabled | Code fix | 
|---|---|---|---|---|---|
| MA0001 | Usage | StringComparison is missing | ℹ️ | ✔️ | ✔️ | 
| MA0002 | Usage | IEqualityComparer<string> or IComparer<string> is missing | ✔️ | ✔️ | |
| MA0003 | Style | Add parameter name to improve readability | ℹ️ | ✔️ | ✔️ | 
| MA0004 | Usage | Use Task.ConfigureAwait | ✔️ | ✔️ | |
| MA0005 | Performance | Use Array.Empty<T>() | ✔️ | ✔️ | |
| MA0006 | Usage | Use String.Equals instead of equality operator | ✔️ | ✔️ | |
| MA0007 | Style | Add a comma after the last value | ℹ️ | ✔️ | ✔️ | 
| MA0008 | Performance | Add StructLayoutAttribute | ✔️ | ✔️ | |
| MA0009 | Security | Add regex evaluation timeout | ✔️ | ❌ | |
| MA0010 | Design | Mark attributes with AttributeUsageAttribute | ✔️ | ✔️ | |
| MA0011 | Usage | IFormatProvider is missing | ✔️ | ❌ | |
| MA0012 | Design | Do not raise reserved exception type | ✔️ | ❌ | |
| MA0013 | Design | Types should not extend System.ApplicationException | ✔️ | ❌ | |
| MA0014 | Design | Do not raise System.ApplicationException type | ✔️ | ❌ | |
| MA0015 | Usage | Specify the parameter name in ArgumentException | ✔️ | ❌ | |
| MA0016 | Design | Prefer using collection abstraction instead of implementation | ✔️ | ❌ | |
| MA0017 | Design | Abstract types should not have public or internal constructors | ✔️ | ✔️ | |
| MA0018 | Design | Do not declare static members on generic types (deprecated; use CA1000 instead) | ℹ️ | ✔️ | ❌ | 
| MA0019 | Usage | Use EventArgs.Empty | ✔️ | ✔️ | |
| MA0020 | Performance | Use direct methods instead of LINQ methods | ℹ️ | ✔️ | ✔️ | 
| MA0021 | Usage | Use StringComparer.GetHashCode instead of string.GetHashCode | ✔️ | ✔️ | |
| MA0022 | Design | Return Task.FromResult instead of returning null | ✔️ | ✔️ | |
| MA0023 | Performance | Add RegexOptions.ExplicitCapture | ✔️ | ❌ | |
| MA0024 | Usage | Use an explicit StringComparer when possible | ✔️ | ✔️ | |
| MA0025 | Design | Implement the functionality instead of throwing NotImplementedException | ✔️ | ❌ | |
| MA0026 | Design | Fix TODO comment | ✔️ | ❌ | |
| MA0027 | Usage | Prefer rethrowing an exception implicitly | ✔️ | ✔️ | |
| MA0028 | Performance | Optimize StringBuilder usage | ℹ️ | ✔️ | ✔️ | 
| MA0029 | Performance | Combine LINQ methods | ℹ️ | ✔️ | ✔️ | 
| MA0030 | Performance | Remove useless OrderBy call | ✔️ | ✔️ | |
| MA0031 | Performance | Optimize Enumerable.Count() usage | ℹ️ | ✔️ | ✔️ | 
| MA0032 | Usage | Use an overload with a CancellationToken argument | ℹ️ | ❌ | ❌ | 
| MA0033 | Design | Do not tag instance fields with ThreadStaticAttribute | ✔️ | ❌ | |
| MA0035 | Usage | Do not use dangerous threading methods | ✔️ | ❌ | |
| MA0036 | Design | Make class static | ℹ️ | ✔️ | ✔️ | 
| MA0037 | Usage | Remove empty statement | ❌ | ✔️ | ✔️ | 
| MA0038 | Design | Make method static (deprecated, use CA1822 instead) | ℹ️ | ✔️ | ✔️ | 
| MA0039 | Security | Do not write your own certificate validation method | ❌ | ✔️ | ❌ | 
| MA0040 | Usage | Forward the CancellationToken parameter to methods that take one | ℹ️ | ✔️ | ✔️ | 
| MA0041 | Design | Make property static (deprecated, use CA1822 instead) | ℹ️ | ✔️ | ✔️ | 
| MA0042 | Design | Do not use blocking calls in an async method | ℹ️ | ✔️ | ✔️ | 
| MA0043 | Usage | Use nameof operator in ArgumentException | ℹ️ | ✔️ | ✔️ | 
| MA0044 | Performance | Remove useless ToString call | ℹ️ | ✔️ | ✔️ | 
| MA0045 | Design | Do not use blocking calls in a sync method (need to make calling method async) | ℹ️ | ❌ | ✔️ | 
| MA0046 | Design | Use EventHandler<T> to declare events | ✔️ | ❌ | |
| MA0047 | Design | Declare types in namespaces | ✔️ | ❌ | |
| MA0048 | Design | File name must match type name | ✔️ | ❌ | |
| MA0049 | Design | Type name should not match containing namespace | ❌ | ✔️ | ❌ | 
| MA0050 | Design | Validate arguments correctly in iterator methods | ℹ️ | ✔️ | ✔️ | 
| MA0051 | Design | Method is too long | ✔️ | ❌ | |
| MA0052 | Performance | Replace constant Enum.ToString with nameof | ℹ️ | ✔️ | ✔️ | 
| MA0053 | Design | Make class or record sealed | ℹ️ | ✔️ | ✔️ | 
| MA0054 | Design | Embed the caught exception as innerException | ✔️ | ❌ | |
| MA0055 | Design | Do not use finalizer | ✔️ | ❌ | |
| MA0056 | Design | Do not call overridable members in constructor | ✔️ | ❌ | |
| MA0057 | Naming | Class name should end with 'Attribute' | ℹ️ | ✔️ | ❌ | 
| MA0058 | Naming | Class name should end with 'Exception' | ℹ️ | ✔️ | ❌ | 
| MA0059 | Naming | Class name should end with 'EventArgs' | ℹ️ | ✔️ | ❌ | 
| MA0060 | Design | The value returned by Stream.Read/Stream.ReadAsync is not used | ✔️ | ❌ | |
| MA0061 | Design | Method overrides should not change default values | ✔️ | ✔️ | |
| MA0062 | Design | Non-flags enums should not be marked with "FlagsAttribute" | ✔️ | ❌ | |
| MA0063 | Performance | Use Where before OrderBy | ℹ️ | ✔️ | ❌ | 
| MA0064 | Design | Avoid locking on publicly accessible instance | ✔️ | ❌ | |
| MA0065 | Performance | Default ValueType.Equals or HashCode is used for struct equality | ✔️ | ❌ | |
| MA0066 | Performance | Hash table unfriendly type is used in a hash table | ✔️ | ❌ | |
| MA0067 | Design | Use Guid.Empty | ℹ️ | ✔️ | ✔️ | 
| MA0068 | Design | Invalid parameter name for nullable attribute | ✔️ | ❌ | |
| MA0069 | Design | Non-constant static fields should not be visible | ✔️ | ❌ | |
| MA0070 | Design | Obsolete attributes should include explanations | ✔️ | ❌ | |
| MA0071 | Style | Avoid using redundant else | ℹ️ | ✔️ | ✔️ | 
| MA0072 | Design | Do not throw from a finally block | ✔️ | ❌ | |
| MA0073 | Style | Avoid comparison with bool constant | ℹ️ | ✔️ | ✔️ | 
| MA0074 | Usage | Avoid implicit culture-sensitive methods | ✔️ | ✔️ | |
| MA0075 | Design | Do not use implicit culture-sensitive ToString | ℹ️ | ✔️ | ❌ | 
| MA0076 | Design | Do not use implicit culture-sensitive ToString in interpolated strings | ℹ️ | ✔️ | ❌ | 
| MA0077 | Design | A class that provides Equals(T) should implement IEquatable<T> | ✔️ | ✔️ | |
| MA0078 | Performance | Use 'Cast' instead of 'Select' to cast | ℹ️ | ✔️ | ✔️ | 
| MA0079 | Usage | Forward the CancellationToken using .WithCancellation() | ℹ️ | ✔️ | ✔️ | 
| MA0080 | Usage | Use a cancellation token using .WithCancellation() | ℹ️ | ❌ | ❌ | 
| MA0081 | Design | Method overrides should not omit params keyword | ✔️ | ✔️ | |
| MA0082 | Design | NaN should not be used in comparisons | ✔️ | ❌ | |
| MA0083 | Design | ConstructorArgument parameters should exist in constructors | ✔️ | ❌ | |
| MA0084 | Design | Local variables should not hide other symbols | ✔️ | ❌ | |
| MA0085 | Usage | Anonymous delegates should not be used to unsubscribe from Events | ✔️ | ❌ | |
| MA0086 | Design | Do not throw from a finalizer | ✔️ | ❌ | |
| MA0087 | Design | Parameters with [DefaultParameterValue] attributes should also be marked [Optional] | ✔️ | ❌ | |
| MA0088 | Design | Use [DefaultParameterValue] instead of [DefaultValue] | ✔️ | ❌ | |
| MA0089 | Performance | Optimize string method usage | ℹ️ | ✔️ | ✔️ | 
| MA0090 | Design | Remove empty else/finally block | ℹ️ | ✔️ | ❌ | 
| MA0091 | Usage | Sender should be 'this' for instance events | ✔️ | ✔️ | |
| MA0092 | Usage | Sender should be 'null' for static events | ✔️ | ❌ | |
| MA0093 | Usage | EventArgs should not be null | ✔️ | ✔️ | |
| MA0094 | Design | A class that provides CompareTo(T) should implement IComparable<T> | ✔️ | ❌ | |
| MA0095 | Design | A class that implements IEquatable<T> should override Equals(object) | ✔️ | ❌ | |
| MA0096 | Design | A class that implements IComparable<T> should also implement IEquatable<T> | ✔️ | ❌ | |
| MA0097 | Design | A class that implements IComparable<T> or IComparable should override comparison operators | ✔️ | ❌ | |
| MA0098 | Performance | Use indexer instead of LINQ methods | ℹ️ | ✔️ | ✔️ | 
| MA0099 | Usage | Use Explicit enum value instead of 0 | ✔️ | ❌ | |
| MA0100 | Usage | Await task before disposing of resources | ✔️ | ❌ | |
| MA0101 | Usage | String contains an implicit end of line character | 👻 | ✔️ | ✔️ | 
| MA0102 | Design | Make member readonly | ℹ️ | ✔️ | ✔️ | 
| MA0103 | Usage | Use SequenceEqual instead of equality operator | ✔️ | ✔️ | |
| MA0104 | Design | Do not create a type with a name from the BCL | ❌ | ❌ | |
| MA0105 | Performance | Use the lambda parameters instead of using a closure | ℹ️ | ✔️ | ❌ | 
| MA0106 | Performance | Avoid closure by using an overload with the 'factoryArgument' parameter | ℹ️ | ✔️ | ❌ | 
| MA0107 | Design | Do not use object.ToString | ℹ️ | ❌ | ❌ | 
| MA0108 | Usage | Remove redundant argument value | ℹ️ | ✔️ | ✔️ | 
| MA0109 | Design | Consider adding an overload with a Span<T> or Memory<T> | ℹ️ | ❌ | ❌ | 
| MA0110 | Performance | Use the Regex source generator | ℹ️ | ✔️ | ✔️ | 
| MA0111 | Performance | Use string.Create instead of FormattableString | ℹ️ | ✔️ | ✔️ | 
| MA0112 | Performance | Use 'Count > 0' instead of 'Any()' | ℹ️ | ❌ | ❌ | 
| MA0113 | Design | Use DateTime.UnixEpoch | ℹ️ | ✔️ | ✔️ | 
| MA0114 | Design | Use DateTimeOffset.UnixEpoch | ℹ️ | ✔️ | ✔️ | 
| MA0115 | Usage | Unknown component parameter | ✔️ | ❌ | |
| MA0116 | Design | Parameters with [SupplyParameterFromQuery] attributes should also be marked as [Parameter] | ✔️ | ✔️ | |
| MA0117 | Design | Parameters with [EditorRequired] attributes should also be marked as [Parameter] | ✔️ | ✔️ | |
| MA0118 | Design | [JSInvokable] methods must be public | ✔️ | ❌ | |
| MA0119 | Design | JSRuntime must not be used in OnInitialized or OnInitializedAsync | ✔️ | ❌ | |
| MA0120 | Performance | Use InvokeVoidAsync when the returned value is not used | ℹ️ | ✔️ | ✔️ | 
| MA0121 | Design | Do not overwrite parameter value | ℹ️ | ❌ | ❌ | 
| MA0122 | Design | Parameters with [SupplyParameterFromQuery] attributes are only valid in routable components (@page) | ℹ️ | ✔️ | ❌ | 
| MA0123 | Design | Sequence number must be a constant | ✔️ | ❌ | |
| MA0124 | Design | Log parameter type is not valid | ✔️ | ❌ | |
| MA0125 | Design | The list of log parameter types contains an invalid type | ✔️ | ❌ | |
| MA0126 | Design | The list of log parameter types contains a duplicate | ✔️ | ❌ | |
| MA0127 | Usage | Use String.Equals instead of is pattern | ❌ | ❌ | |
| MA0128 | Usage | Use 'is' operator instead of SequenceEqual | ℹ️ | ✔️ | ✔️ | 
| MA0129 | Usage | Await task in using statement | ✔️ | ❌ | |
| MA0130 | Usage | GetType() should not be used on System.Type instances | ✔️ | ❌ | |
| MA0131 | Usage | ArgumentNullException.ThrowIfNull should not be used with non-nullable types | ✔️ | ❌ | |
| MA0132 | Design | Do not convert implicitly to DateTimeOffset | ✔️ | ❌ | |
| MA0133 | Design | Use DateTimeOffset instead of relying on the implicit conversion | ℹ️ | ✔️ | ❌ | 
| MA0134 | Usage | Observe result of async calls | ✔️ | ❌ | |
| MA0135 | Design | The log parameter has no configured type | ❌ | ❌ | |
| MA0136 | Usage | Raw String contains an implicit end of line character | 👻 | ✔️ | ❌ | 
| MA0137 | Design | Use 'Async' suffix when a method returns an awaitable type | ❌ | ❌ | |
| MA0138 | Design | Do not use 'Async' suffix when a method does not return an awaitable type | ❌ | ❌ | |
| MA0139 | Design | Log parameter type is not valid | ✔️ | ❌ | |
| MA0140 | Design | Both if and else branch have identical code | ✔️ | ❌ | |
| MA0141 | Usage | Use pattern matching instead of inequality operators for null check | ℹ️ | ❌ | ✔️ | 
| MA0142 | Usage | Use pattern matching instead of equality operators for null check | ℹ️ | ❌ | ✔️ | 
| MA0143 | Design | Primary constructor parameters should be readonly | ✔️ | ❌ | |
| MA0144 | Performance | Use System.OperatingSystem to check the current OS | ✔️ | ❌ | |
| MA0145 | Usage | Signature for [UnsafeAccessorAttribute] method is not valid | ✔️ | ❌ | |
| MA0146 | Usage | Name must be set explicitly on local functions | ✔️ | ❌ | |
| MA0147 | Usage | Avoid async void method for delegate | ✔️ | ❌ | |
| MA0148 | Usage | Use pattern matching instead of equality operators for discrete value | ℹ️ | ❌ | ✔️ | 
| MA0149 | Usage | Use pattern matching instead of inequality operators for discrete value | ℹ️ | ❌ | ✔️ | 
| MA0150 | Design | Do not call the default object.ToString explicitly | ✔️ | ❌ | |
| MA0151 | Usage | DebuggerDisplay must contain valid members | ✔️ | ❌ | |
| MA0152 | Performance | Use Unwrap instead of using await twice | ℹ️ | ✔️ | ❌ | 
| MA0153 | Design | Do not log symbols decorated with DataClassificationAttribute directly | ✔️ | ❌ | |
| MA0154 | Design | Use langword in XML comment | ℹ️ | ✔️ | ✔️ | 
| MA0155 | Design | Do not use async void methods | ❌ | ❌ | |
| MA0156 | Design | Use 'Async' suffix when a method returns IAsyncEnumerable<T> | ❌ | ❌ | |
| MA0157 | Design | Do not use 'Async' suffix when a method returns IAsyncEnumerable<T> | ❌ | ❌ | |
| MA0158 | Performance | Use System.Threading.Lock | ✔️ | ❌ | |
| MA0159 | Performance | Use 'Order' instead of 'OrderBy' | ℹ️ | ✔️ | ✔️ | 
| MA0160 | Performance | Use ContainsKey instead of TryGetValue | ℹ️ | ✔️ | ❌ | 
| MA0161 | Usage | UseShellExecute must be explicitly set | ℹ️ | ❌ | ❌ | 
| MA0162 | Usage | Use Process.Start overload with ProcessStartInfo | ℹ️ | ❌ | ❌ | 
| MA0163 | Usage | UseShellExecute must be false when redirecting standard input or output | ✔️ | ❌ | |
| MA0164 | Style | Use parentheses to make not pattern clearer | ✔️ | ✔️ | |
| MA0165 | Usage | Make interpolated string | 👻 | ✔️ | ✔️ | 
| MA0166 | Usage | Forward the TimeProvider to methods that take one | ℹ️ | ✔️ | ✔️ | 
| MA0167 | Usage | Use an overload with a TimeProvider argument | ℹ️ | ❌ | ❌ | 
| MA0168 | Performance | Use readonly struct for in or ref readonly parameter | ℹ️ | ❌ | ❌ | 
| MA0169 | Design | Use Equals method instead of operator | ✔️ | ❌ | |
| MA0170 | Design | Type cannot be used as an attribute argument | ❌ | ❌ | |
| MA0171 | Usage | Use pattern matching instead of HasValue for Nullable<T> check | ℹ️ | ❌ | ✔️ | 
| MA0172 | Usage | Both sides of the logical operation are identical | ❌ | ❌ | |
| MA0173 | Design | Use LazyInitializer.EnsureInitialize | ℹ️ | ✔️ | ❌ | 
| MA0174 | Style | Record should use explicit 'class' keyword | ℹ️ | ❌ | ❌ | 
| MA0175 | Style | Record should not use explicit 'class' keyword | ℹ️ | ❌ | ❌ | 
| MA0176 | Performance | Optimize guid creation | ℹ️ | ✔️ | ✔️ | 
| MA0177 | Style | Use single-line XML comment syntax when possible | ℹ️ | ❌ | ✔️ | 
| Id | Suppressed rule | Justification | 
|---|---|---|
MAS0001 | 
CA1822 | Suppress CA1822 on methods decorated with BenchmarkDotNet attributes. | 
MAS0002 | 
CA1822 | Suppress CA1822 on methods decorated with a System.Text.Json attribute such as [JsonPropertyName] or [JsonInclude]. | 
MAS0003 | 
IDE0058 | Suppress IDE0058 on well-known types | 
MAS0004 | 
CA1507 | Suppress CA1507 on methods decorated with a [Newtonsoft.Json.JsonPropertyAttribute]. | 
You can set the <MeziantouAnalysisMode> MSBuild property to configure the default severity of the rules. The default value is Default. You can set it to None to disable all rules by default.
<Project>
  <PropertyGroup>
    <MeziantouAnalysisMode>None</MeziantouAnalysisMode>
  </PropertyGroup>
</Project>