-
-
Notifications
You must be signed in to change notification settings - Fork 63
docs: enhance MA0090 and MA0098 rule documentation #874
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
meziantou
merged 7 commits into
meziantou:main
from
Meir017:docs/enhance-ma0090-ma0098-documentation
Sep 27, 2025
Merged
Changes from 5 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
5b4911c
docs: enhance MA0090 and MA0098 rule documentation
Meir017 31d065f
docs: simplify MA0098 examples section based on PR feedback
Meir017 c87286d
docs: remove Related Rules section from MA0098 for consistency
Meir017 aad6f80
docs: simplify MA0090 documentation structure to match standard format
Meir017 1ae51e7
Merge branch 'main' into docs/enhance-ma0090-ma0098-documentation
Meir017 f92f4a2
Remove sections on performance benefits and exceptions
meziantou 65f27d8
Merge branch 'main' into docs/enhance-ma0090-ma0098-documentation
meziantou File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,65 @@ | ||
| # MA0090 - Remove empty else/finally block | ||
|
|
||
| This rule detects empty `else` and `finally` blocks that contain no executable code and suggests removing them to improve code readability and reduce clutter. Empty blocks serve no functional purpose and can make code harder to read by adding unnecessary visual noise. | ||
|
|
||
| ````csharp | ||
| // non-compliant | ||
| if (condition) | ||
| { | ||
| DoSomething(); | ||
| } | ||
| else | ||
| { | ||
| } | ||
|
|
||
| // compliant | ||
| if (condition) | ||
| { | ||
| DoSomething(); | ||
| } | ||
|
|
||
| // non-compliant | ||
| try | ||
| { | ||
| DoSomething(); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| HandleException(ex); | ||
| } | ||
| finally | ||
| { | ||
| } | ||
|
|
||
| // compliant | ||
| try | ||
| { | ||
| DoSomething(); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| HandleException(ex); | ||
| } | ||
|
|
||
| // compliant - blocks with comments are not flagged | ||
| if (condition) | ||
| { | ||
| DoSomething(); | ||
| } | ||
| else | ||
| { | ||
| // TODO: Implement this feature later | ||
| } | ||
|
|
||
| // compliant - blocks with preprocessor directives are not flagged | ||
| try | ||
| { | ||
| DoSomething(); | ||
| } | ||
| finally | ||
| { | ||
| #if DEBUG | ||
| Console.WriteLine("Debug mode"); | ||
| #endif | ||
| } | ||
| ```` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,86 @@ | ||
| # MA0098 - Use indexer instead of LINQ methods | ||
|
|
||
| When working with collections that support indexing (such as arrays, `List<T>`, `IList<T>`, or `IReadOnlyList<T>`), using the indexer syntax `[index]` is more efficient than LINQ methods like `ElementAt()`, `First()`, and `Last()`. This rule suggests replacing these LINQ methods with direct indexer access for better performance. | ||
|
|
||
| The indexer approach provides direct access to elements without the overhead of LINQ extension methods and enumeration, resulting in faster execution and reduced memory allocations. | ||
|
|
||
| ## Examples | ||
|
|
||
| ````csharp | ||
| var list = new List<int>(); | ||
|
|
||
| _ = list.ElementAt(5); // non-compliant | ||
| _ = list[5]; // compliant | ||
|
|
||
| _ = list.First(); // non-compliant | ||
| _ = list[0]; // compliant | ||
|
|
||
| _ = list.Last(); // non-compliant | ||
| _ = list[^1]; // compliant | ||
| _ = list[list.Count - 1]; // compliant | ||
|
|
||
| _ = list.FirstOrDefault(); // compliant | ||
| _ = list.First(x => x > 1); // compliant | ||
| ```` | ||
|
|
||
| ## C# 8+ Index and Range Support | ||
|
|
||
| Starting with C# 8.0 and when targeting frameworks that support the Index and Range feature (.NET Core 3.0+, .NET 5+), the analyzer can suggest using the hat operator (`^`) for accessing elements from the end: | ||
|
|
||
| ````csharp | ||
| // C# 8+ with compatible target framework | ||
| var array = new int[10]; | ||
|
|
||
| // The analyzer suggests using the hat operator for Last() | ||
| var last = array[^1]; // ✅ Equivalent to array[array.Length - 1] | ||
|
|
||
| // For older language versions or target frameworks, it uses the traditional syntax | ||
| var last = array[array.Length - 1]; // ✅ Fallback for older versions | ||
| ```` | ||
|
|
||
| ## Performance Benefits | ||
|
|
||
| Using indexer access instead of LINQ methods provides several performance advantages: | ||
|
|
||
| - **Direct Access**: Indexers provide O(1) direct access to elements, while LINQ methods may involve enumeration overhead | ||
| - **No Extension Method Overhead**: Eliminates the cost of extension method calls and delegate invocations | ||
| - **Reduced Memory Allocations**: Avoids temporary objects and iterator allocations that LINQ methods might create | ||
| - **Better JIT Optimization**: The JIT compiler can better optimize simple indexer access compared to generic extension methods | ||
|
|
||
| ## When This Rule Doesn't Apply | ||
|
|
||
| This rule has specific limitations and won't trigger in certain scenarios: | ||
|
|
||
| ### Methods with Predicates | ||
|
|
||
| The rule only applies to parameterless versions of `First()` and `Last()`, and single-parameter `ElementAt()`. It doesn't apply when using predicates: | ||
|
|
||
| ````csharp | ||
| // These are NOT flagged by the rule - predicates are necessary | ||
| var firstEven = list.First(x => x % 2 == 0); | ||
| var lastNegative = array.Last(x => x < 0); | ||
| ```` | ||
|
|
||
| ### OrDefault Variants | ||
|
|
||
| The rule doesn't apply to the "OrDefault" variants of these methods: | ||
|
|
||
| ````csharp | ||
| // These are NOT flagged by the rule | ||
| var item1 = list.FirstOrDefault(); // ✅ Rule doesn't apply | ||
| var item2 = list.LastOrDefault(); // ✅ Rule doesn't apply | ||
| var item3 = list.ElementAtOrDefault(5); // ✅ Rule doesn't apply | ||
| ```` | ||
|
|
||
| ### Unsupported Collection Types | ||
|
|
||
| The rule only applies to collections that implement `IList<T>` or `IReadOnlyList<T>`: | ||
|
|
||
| ````csharp | ||
| // These are NOT flagged by the rule - no indexer support | ||
| IEnumerable<int> enumerable = GetNumbers(); | ||
| var first = enumerable.First(); // ✅ Rule doesn't apply | ||
|
|
||
| HashSet<int> hashSet = new(); | ||
| var firstFromSet = hashSet.First(); // ✅ Rule doesn't apply | ||
| ```` | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.