Dotnet logo

.NET Tools

Essential productivity kit for .NET and game developers

.NET Tools How-To's

C# Language Support in ReSharper and Rider 2024.3

Our upcoming 2024.3 release marks a huge milestone for our development process but especially for our users. ReSharper and Rider 2024.3 will be simshipped along with .NET 9 and C# 13! Yes, you heard right—no more waiting an extra few weeks or using our EAP builds to take advantage of the latest and greatest C# of all time. If all goes well (🤞 – update: made it 🫡), you can enjoy your most loved language in your most loved IDE starting tomorrow!

In this blog post, we will cover new features that have been added to our C# language support over the 2024.3 release cycle. Note that some C# 13 features have already been covered in the 2024.2 release, including escape characters and ref struct interfaces. Make sure to check out our three-part series if you’ve missed it!

Partial Properties

One of the most anticipated features in C# 13 are partial properties. Previously, the concept of partial members was limited to types and methods. While partial types (classes, structs, records) mainly help organize your code into multiple parts and avoid cluttered single files, partial members allow you to define a single member (methods, properties, indexers) in any of these parts with only one part implementing it. This concept becomes particularly powerful in combination with source generators that automatically provide the correct and optimized implementation based on your member definitions:

// User code
public partial Person : INotifyPropertyChanged
{
    [JsonPropertyName("custom-name")]
    public partial string Name { get; set; }
}

// Generated code
partial Person
{
    // More attributes allowed!
    public partial string Name
    {
        get => field;
        set => SetField(ref field, value);
    }
    // ...
}
Copy to clipboard

With ReSharper and Rider 2024.3, we are adding support for partial properties syntax and updating our code highlightings and generators. For instance, you can generate property definitions through:

  1. The Implement property in another part of class quick-fix
    Implementing a partial property in another part of the type
    Implementing a partial property in another part of the type
  2. The Generate Partial Members action from the Alt+Enter menu
    Generating multiple partial properties
    Generating multiple partial properties
  3. The code completion after typing partial
    Code completion for missing partial properties
    Code completion for missing partial properties

You will also find new and updated context actions to manage existing partial definitions. For instance, you can change the accessibility from one part of a member definition, and it will reflect on all the other parts:

Changing access modifiers or partial properties
Changing access modifiers or partial properties

Or you can merge partial members into one definition:

Merging partial properties into one definition
Merging partial properties into one definition

Field Keyword

The long-awaited field keyword for properties is finally coming to C# 13 as a preview feature. Previously, you had to explicitly declare a backing field for every non-trivial property. With the new field keyword, you can implement semi-auto-properties by referencing the compiler-generated backing field in your custom accessor:

// Before C# 13
class Person
{
    private string _name;
    public string Name
    {
        get => _name;
        set => _name = value.Trim();
    }
}

// From C# 13
class Person
{
    public string Name
    {
        get;
        set => field = value.Trim();
    }
}
Copy to clipboard

Once you’ve added <LangVersion>preview</LangVersion> to your project file, ReSharper and Rider will recognize the old pattern and offer to Replace with ‘field’ keyword:

Replacing backing fields with the field keyword
Replacing backing fields with the field keyword

ReSharper and Rider will also help you to Remove redundant bodies where the property value is only returned or set:

Removing redundant bodies for accessor bodies
Removing redundant bodies for accessor bodies

With this syntax, some popular patterns involving properties become notably compact. For instance, as part of ourINotifyPropertyChanged support, we’ve updated our To property with ‘SetField’ change notification context action to implement properties more efficiently and easy to read:

Implementing property change notifications
Implementing property change notifications

Another very common pattern is input value validation. While previously, you were forced to implement getter/setter accessors and declare a backing field, ReSharper and Rider will now allow you to use parameter-checking context actions to convert to a succinct implementation for just the set or init accessor:

Adding null checks for properties
Adding null checks for properties

To get the most compact formatting layout, make sure to enable Place simple accessor on single line in your code style settings!

Code style settings for property accessors
Code style settings for property accessors

System.Threading.Lock Type

In .NET 9, we are getting a new type System.Threading.Lock designed for thread synchronization. In C#, you can implement thread synchronization through the lock statement over any reference type object. Often, this is done with a private object field that is created solely for locking purposes:

class LockObject
{
    private readonly object _syncRoot = new();

    public void M()
    {
        lock (_syncRoot)
        {
            // work
        }
    }
}
Copy to clipboard

While technically alright, these object fields do not tell how they’re intended to be used apart from their name. Locking is often performed over existing objects accessible to other locking types, which can have unintended side effects. Firstly, entering the block can be unnecessarily delayed from other classes that lock on the same object. Secondly, since the runtime might have to promote the lock when Object.GetHashCode() is called or thread contention happens, the following lock acquisition or release will be slightly more expensive.

The System.Threading.Lock was introduced to solve both of the issues described above. It clearly expresses the intent of fields used for locking, while it also avoids performance degradation. In 2024.3, we detect old field synchronization patterns and offer the replacement with the Lock type:

Converting to System.Threading.Lock in synchronization patterns
Converting to System.Threading.Lock in synchronization patterns

Merge Switch-Case Sections

In our last 2024.2 release, we introduced a new quick-fix Extract Common Code, which can extract common statements from if and switch statements. In the new 2024.3 release, we are extending this family of code duplication fixes with a new quick-fix to merge duplicated switch cases into a single case with broader conditions:

Merging duplicated switch section bodies
Merging duplicated switch section bodies

As a reminder, these inspections can also hint at code that was supposed to be different but ended up unchanged after copy-pasting it. So make sure to carefully investigate each duplication before merging it!

IDE Tooltips Colorization

As with every release, we not only focus on supporting new language features but also enhancing existing functionality to ensure our .NET IDEs stay aligned with modern IDE capabilities. In this release, we reviewed nearly all C# errors, warnings, and informational messages to introduce editor-like text colorization wherever possible. Overall, approximately 600 messages were upgraded, making many of the tooltips you see daily more structured and easier to read:

Colorization and cleanup of tooltips
Colorization and cleanup of tooltips

And this is just the beginning—utilizing the colorization infrastructure, we plan to enhance other error messages, particularly type conversion errors. During the refactoring, we also introduced colorization in various other editor tooltips and popups:

Colorization of classes in ‘missing references’ popup (Rider only)
Colorization of classes in ‘missing references’ popup (Rider only)
Colorization of classes in type hierarchy popup (ReSharper only)
Colorization of classes in type hierarchy popup (ReSharper only)

Obsolete and EditorBrowsable

Over many years, we’ve been struggling to properly support [Obsolete] and [EditorBrowsable] in our code completion. That is mainly because we cannot afford to ask each code entity in a completion list (types, members) about its traits regarding these two attributes. Caching, one of the most obvious solutions, is not well-suited for the source code domain, where code semantics can change drastically with each keypress. However, it can be effective for compiled code from assemblies, though it has the drawback of using more memory and performance on the first read.

In 2024.3, we’ve managed to find the sweet spot of trade-offs to support both the [Obsolete] and [EditorBrowsable] attributes while also ensuring that the IDE performance remains unaffected. Types and members marked as obsolete are now de-prioritized in the completion list sorting. This should be particularly useful for Unity developers, where some common base classes have many obsolete members. Types and members marked with EditorBrowsableState.Never are filtered out from the list by default:

Filtering and sorting in code completion lists
Filtering and sorting in code completion lists

You can change the filter behavior for the [EditorBrowsable] attribute in the code completion settings:

Code completion settings for the [EditorBrowsable] attribute
Code completion settings for the [EditorBrowsable] attribute

Operation Priority Quick-Fixes

In C#, certain operations, such as enum flag checks or nested ternary conditional expressions, may require extra parentheses to ensure correct priority and readability. Adding these parentheses manually can be cumbersome and disrupt your coding flow. To streamline this, we’ve introduced a Prioritize operation using parentheses quick-fix that automatically inserts any necessary parentheses in these common scenarios, allowing you to focus on more critical aspects of your code:

Prioritizing operations using parentheses
Prioritizing operations using parentheses

Conclusion

.NET 9 and C# 13 bring powerful advancements in runtime and language. ReSharper and Rider are here to complement them with the best-in-class and most productive IDE experience! 🎤👋

As always—make sure to use the comment section below to let us know about other features around .NET and C# you’d like to see in your developer toolbox!

image description

Discover more