.NET Tools
Essential productivity kit for .NET and game developers
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);
}
// ...
}
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:
- The Implement property in another part of class quick-fix
- The Generate Partial Members action from the Alt+Enter menu
- The code completion after typing
partial
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:
Or you can merge partial members 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();
}
}
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:
ReSharper and Rider will also help you to Remove redundant bodies where the property value is only returned or set:
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:
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:
To get the most compact formatting layout, make sure to enable Place simple accessor on single line in your code style settings!
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
}
}
}
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:
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:
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:
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:
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:
You can change the filter behavior for the [EditorBrowsable]
attribute in the code completion settings:
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:
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!