C# Language Support in ReSharper and Rider 2025.1

Our release for ReSharper and Rider 2025.1 is just around the corner, and we have lots of exciting features shipping for the current and next version of C#! This will be a really long post (blame our awesome devs!), so make sure to use the table of contents on the right. Oh, and of course… […]

Apr 10, 2025 - 19:51
 0
C# Language Support in ReSharper and Rider 2025.1

Our release for ReSharper and Rider 2025.1 is just around the corner, and we have lots of exciting features shipping for the current and next version of C#! This will be a really long post (blame our awesome devs!), so make sure to use the table of contents on the right. Oh, and of course…

For many of the inspections and quick fixes discussed in this post, we recommend using either find in scope or fix in scope to effectively use them in your codebases. Now, let’s talk about new features!

Structured Logging Support

In ReSharper and Rider 2025.1, we enhanced support for structured and high-performance logging using the Microsoft.Extensions.Logging APIs. Similar to how formatting arguments are highlighted in string.Format using the {0} syntax, we now highlight the corresponding type arguments in the Logger.Define and LoggerMessageAttribute API. Additionally, missing type arguments are now reported with diagnostics to catch issues early, along with quick-fixes and context actions to add or remove them as needed:

Structured and High-Performance Logging Support
Structured and High-Performance Logging Support

String Construction Context Actions

Our .NET IDEs offer a wide range of suggestions and context actions for working with C# string literals, interpolated strings, string.Format, and StringBuilder constructs. You can convert nearly any string-related expression into various other forms to enhance readability or to better parameterize string construction.

However, some conversion directions were still missing. For example, while it’s been easy to convert a concatenated string like "Id = " + someId into either an interpolated string $"Id = {someId}" or a format string string.Format("Id = {0}", someId), there hasn’t been a way to reverse this — i.e., to convert interpolated or formatted strings back into concatenation. In certain scenarios, such a transformation can actually result in more concise or readable code:

Convert Interpolation to Concatenation Context Action
Convert Interpolation to Concatenation Context Action

Improved Multiline To-Do Comments

In the previous release, we introduced support for multiline to-do comments, where subsequent lines were considered part of the same item based on their indentation. In the 2025.1 release, we’ve enhanced this feature by making indentation optional. Now, lines following a to-do comment are automatically treated as part of the same item, even without indentation, making multiline comments more intuitive and seamless. However, if indentation is used, it will be strictly enforced:

Improved Multiline To-Do Comments
Improved Multiline To-Do Comments

Language Injection in Return Values

Language injection made its debut in ReSharper around 10 years ago with support for regular expressions. Since then, it has been brought to Rider, expanded to other languages, and updated to work with new language and runtime features.

Previously, the LanguageInjection attribute (from JetBrains.Annotations) could only be applied to parameters, fields, and properties. Now you can annotate methods to specify that their returned strings represent an embedded code of another language:

Language Injection in Return Values
Language Injection in Return Values

Redundant Duplicated Code

In the previous two versions, we introduced inspections for more specific scenarios of code duplication — common code in if and switch statements and duplicated switch section bodies. In this 2025.1 release, we deliver three new inspections to help you eliminate unintentional duplications and improve readability and maintainability in your codebase.

Our first inspection detects duplicated statements that appear both within conditional branches of if and switch statements ending with jump statements and again immediately afterward:

Duplicated Statements in Conditional Branches Inspection and Quick-Fix
Duplicated Statements in Conditional Branches Inspection and Quick-Fix

Another inspection detects redundant arms in switch expressions — specifically, arms that return the same value as the default one. Removing these redundancies simplifies your code and improves readability:

Redundant switch Expression Arms Inspection and Quick-Fix
Redundant switch Expression Arms Inspection and Quick-Fix

The last inspection detects when multiple if branches execute identical code and provides a handy quick-fix to merge them:

Duplicated if Bodies Inspection and Quick-Fix
Duplicated if Bodies Inspection and Quick-Fix

Misuse of CancellationToken

When working with asynchronous methods, it’s common to pass a CancellationToken through parameters of local functions or lambda expressions. Accidentally using a method-level token instead of a more specific, locally scoped one can lead to unintended behavior, such as tasks not being canceled when expected.

ReSharper and Rider 2025.1 introduce a new inspection that detects when a broader-scoped cancellation token is mistakenly used instead of a more appropriate local token available within a local function or lambda. You can choose from two corresponding quick-fixes to either a) replace the mistakenly used token with the correct local token, or b) link both tokens into one using CancellationTokenSource.CreateLinkedTokenSource:

Possibly Mistaken Use of CancellationToken Inspection
Possibly Mistaken Use of CancellationToken Inspection

Injection Postfix Template

Primary constructors in C# 12 greatly simplify constructor dependency injection patterns. You only need to mention a dependency once in the constructor parameter list, and it automatically becomes available across all instance members of the class without the need to define and assign a field explicitly.

In ReSharper and Rider 2025.1, we introduce a new inject postfix template available for type names. When you realize you need to add a dependency on IService, select it from the completion list, append .inject, and hit your completion key:

Inject Postfix Template
Inject Postfix Template

Transform Parameters Refactoring

The transform parameters refactoring makes it easy to change a method’s signature by modifying its parameters — for example, removing out parameters, wrapping them in a tuple or a new class, and more — while automatically updating all usages of the method across your solution.

With ReSharper and Rider 2025.1, we reworked the refactoring to support modern language features (including tuple types, record classes, and primary constructors), treat tuple elements as multiple return values, transform ref parameters into both input and output values, and handle lots of deconstruction usages. Bring up the dialog, select the parameters you want to transform, and choose your desired target types:

Transform Parameters Refactoring Dialog
Transform Parameters Refactoring Dialog

Context Highlighters for Extended Types

One of the very subtle features in ReSharper and Rider is the highlighting of matching code elements (for instance, check out Matching of control flow keywords). From 2025.1, we will help you to visually identify members that extend the base class or implement some concrete interface type. Just place the caret over the type name in the base types clause:

Context Highlighters for Extended and Implemented Members
Context Highlighters for Extended and Implemented Members

Chop Formatting Context Action

Our built-in formatter helps you to align your code with your preferred code formatting style settings. It can be invoked manually, through an “on-save” action, or before committing changes. Sometimes, though, you may want more control without triggering widespread formatting. A new context action lets you apply chop formatting to various C# constructs directly without needing to make a selection:

Chop Parameters List Context Action
Chop Parameters List Context Action

Modification in Debug.Assert

When writing code assertions using APIs like Debug.Assert, it’s easy to forget that these calls are stripped out in RELEASE builds. This is because methods marked with attributes like [Conditional("DEBUG")] are only compiled when the DEBUG symbol is defined in the project. As a result, if the assertion condition includes side effects — such as assignments or collection mutations — those side effects will not occur in RELEASE builds. These conditional side effects are hard to spot and reason about, and they can lead to subtle bugs or unexpected behavior.

Our new 2025.1 code inspection detects and warns you about such cases automatically:

Modifications in Debug.Assert Inspection
Modifications in Debug.Assert Inspection

Inexact Stream Reads

A common mistake when working with .NET’s Stream class is misusing the Read and ReadAsync methods. These methods accept a buffer (an array or a Span) and are often assumed to fill it completely — but they are not guaranteed to do so. Crucially, Stream implementations are allowed to return partial data and will report the actual number of bytes read, which may be less than the buffer size. That’s why it’s essential to handle the return value from Read and ReadAsync properly and continue reading until the desired amount of data is received.

Starting with our 2025.1 IDEs, incorrect usage patterns of Read and ReadAsync are automatically detected, with suggestions to replace them with the safer ReadExactly API:

Inexact Stream Reads Inspection and Quick-Fix
Inexact Stream Reads Inspection and Quick-Fix

Tuple Component Names

Tuple types allow you to use both explicit and generic component names. Sometimes, it is overlooked that a component can be referenced by its explicit name, e.g., MyComponent, rather than ItemN. Our new IDE hint and corresponding quick-fix help you to get rid of generic names in favor of explicit names to make your code more readable:

Prefer Explicit Name for Tuple Component Inspection and Quick-Fix
Prefer Explicit Name for Tuple Component Inspection and Quick-Fix

Referencing Enum Member Names

The nameof operator was introduced in C# 6 — another case of “10 years today”! Since then, many have embraced it extensively to reference variable, type, and member names as string constants instead of using magic strings. ReSharper and Rider continue to spot situations [1, 2] in which you can make better use of them. Referencing an enum member through ToString introduces unnecessary runtime overhead due to reflection and additional processing.

In 2025.1, we are adding a new inspection Use nameof expression to reference enum member name that targets such cases and provides a quick-fix to convert to nameof as a compile-time language feature that is faster, safer, and clearer:

Use nameof for Reference Inspection and Quick-Fix
Use nameof for Reference Inspection and Quick-Fix

Nameof with Unbound Generics

Another new feature in C# 14 now allows using the nameof operator with unbound generics. Previously, to get List as a compile-time constant, you had to provide generic arguments — e.g., nameof(List) — even though they are not included in the final name. This friction is now removed, and you can use the open generic as in nameof(List<>).

ReSharper and Rider identify places where generic types in nameof operators can be simplified and provide a quick-fix to remove redundancies:

Redundant Type Arguments in nameof Inspection and Quick-Fix
Redundant Type Arguments in nameof Inspection and Quick-Fix

First-Class Span Types

In recent years, the BCL and many other libraries have extensively adopted Span and ReadOnlySpan to provide more performant APIs. With C# 14, first-class support for span types is introduced through new implicit conversions between ReadOnlySpan, Span, and T[], which are now applied in more scenarios. This makes working with spans more intuitive and seamless. ReSharper and Rider 2025.1 fully support these updated conversion rules:

Span Type Conversion
Span Type Conversion

Simple Lambda Parameters with Modifiers

The next C# update simplifies writing lambda signatures. Previously, using parameter modifiers like ref, out, in, ref readonly, or scoped in lambdas required explicitly specifying the parameter type — for no particular reason. Starting with C# 14, this restriction has been lifted, allowing you to use these modifiers without redundant type annotations.

As you’d expect, ReSharper and Rider 2025.1 offer a quick-fix to remove the now-redundant type specifications:

Redundant Lambda Parameters Inspection and Quick-Fix
Redundant Lambda Parameters Inspection and Quick-Fix

Default Literal Suggestions

C# is well-known for offering multiple ways to express the same concept (looking at you, null checks!). While flexibility has its merits, this kind of redundancy is generally not a good thing. It’s exactly why IDE tooling plays a crucial role in helping developers standardize and streamline code — ensuring consistency and reducing ambiguity.

Using the default literal in non-generic contexts to represent trivial values like 0 or false can make code harder to reason about. ReSharper and Rider now help you catch such cases and offer recommendations to clarify the intent:

Default Literal Inspection and Quick-Fix
Default Literal Inspection and Quick-Fix

Conclusion

Wow — that was a lot to cover! One thing’s clear: our team has poured serious effort into not just flashy new language features but also refining older ones, making them shine in fresh ways.

We’d love to hear from you. Do you spot any issues or have ideas for ReSharper and Rider vNextNext? Drop them in the comments!