Dotnet logo

.NET Tools

Essential productivity kit for .NET and game developers

How-To's

Learning best practices and language features using Rider code inspections

In the previous posts, we have seen how Rider‘s code analysis works and looked at how we can do things like spotting warnings and errors even before compiling and running our application. Rider helps us with such things by continuously validating our code using over 2400 inspections coming from ReSharper and from IntelliJ-based IDEs. In this post, we’ll look at how Rider’s code analysis can help us learn best practices and new language features.

In this series: (table of contents will be updated as we progress)

Learning best practices

Source code is the fabric we use to build solutions to business or technical problems. For any problem, there are many solutions available. And for every pattern, there are a number of anti-patterns. Rider’s code analysis helps in detecting possible improvements, provides quick fixes to apply them, and helps us learn best-practices in the process.

In the following code, range is an IEnumerable which we’re traversing twice: once in the foreach loop, once when calling Sum().

var range = Enumerable.Range(1, 100);

foreach (var element in range)
{
    Console.WriteLine($"* {element}");
}

var sum = range.Sum();

This is not considered good practice, as an enumerable can, in theory, be generating its elements multiple times, doing more work than needed. Imagine if that enumerable would run a database query in the background: we’d be running all those queries twice! Worse: an enumerable may only enumerate once, losing data and introducing unwanted behavior when we try to enumerate it a second time!

Rider’s Possible multiple enumeration of IEnumerable inspection detects this and provides a quick fix (Alt+Enter) that enumerates to an array or list:

Possible multiple enumeration - convert to array or list

Slightly more complex, perhaps, Rider also knows about the dispose pattern in .NET. When we use a system resource like memory, system handles, database connections, file streams etc., the dispose pattern helps in cleaning up those external resources without having to rely on the garbage collector and waiting for the finalizer queue. Rider’s code inspection knows about this interface and can help us implement it. When implementing the IDisposable interface, Rider will offer to do the implementation for us based on the resources we are using in our class (Alt+Enter):

Let Rider help implement the Dispose pattern

Note that we are able to pick some additional options, such as whether fields can be null, whether we plan on inheriting from this class and whether we are using unmanaged resources, etc. The generated code will depend on these options.

When we specify we’re using unmanaged resources, Rider generates a method ReleaseUnmanagedResources (with a TODO comment) where we can release those resources. The surrounding code ensures that this method is called according to best practices.

private void ReleaseUnmanagedResources()
{
    // TODO release unmanaged resources here
}

Another example would be implementing INotifyPropertyChanged. We can use this interface to implement property change notification. Rider knows about this interface, and will suggest adding a proper implementation for us:

Implement INotifyPropertyChanged interface correctly

Not only does Rider implement the interface for us, which would only add the PropertyChangedEventHandler event, but also generates the event handler invocation method, which we can later use in our properties. And thanks to the annotation attributes that are being added, Rider knows our properties may want to provide change notification – so it suggests a quick fix (Alt+Enter) for converting a property to a property with change notification. When invoked, a backing field and call into our event handler invocation method will be added:

Quick fix to convert property to property with change notification

As usual, Rider has this type of code inspections for many languages. For example in JavaScript, it will suggest joining variable declaration and assignment. In HTML, it will inform us that <center> is obsolete and suggests using CSS for alignment instead. We recommend that you explore these inspections – a full list is available in the settings (under Editor | Inspection Settings | Inspection Severity) to get an overview of the many code inspections available.

Learning (new) language features

How can we improve our coding skills? How do we stay up-to-date and learn about new language features (such as those in C# 7 / C# 7.1 / C# 7.2)? Have Rider help us, of course!

Rider comes with several Language Usage Opportunities inspections that teach us new syntax or show us equivalent syntax to do something we’ve been doing since forever.

Back when C# 6 was released, the null-coalescing expressions were extended with conditional access expressions: ?. (nicknamed the Elvis operator, tilt your head to the left). It performs a null check and returns the value if it’s not null. Rider recognizes when we write this type of check and informs us that we can update our code to make use of this language feature.

Using the Elvis opertor to do null checks

In C# 7, local functions were introduced. When Rider recognizes a piece of code that can be converted to a local function, it will suggest doing so using the provided quick fix (Alt+Enter):

Convert FuncT to local function using Rider quick fix

And don’t forget: we can search for language usage opportunities in our entire codebase, too, making it easy to figure out where we can improve or modernize our code. Some inspections can even fix suboptimal code in our entire project or solution at once – for example, convert to using expression bodies:
Fix expression-body code style in solution

Code analysis has many more inspections that can help us master existing or new language features. In JavaScript, among other things, Rider will suggest using a template string instead of string concatenation. For TypeScript, Rider will suggest using the as operator instead of asserting a variable’s type explicitly.

What else is there?

In this post, we’ve demonstrated only a couple of the more than 2400 code inspections borrowed from ReSharper and IntelliJ-based IDEs. In the area of learning best practices and language features, make sure to open the settings under Editor | Inspection Settings | Inspection Severity and explore the various inspections under these categories:

  • Language Usage Opportunities, helping us to learn our programming language. Examples are suggesting optional parameters, converting a for loop into a foreach, …
  • Redundancies in Code, such as detecting empty loops or detecting expressions that are always true or null.
  • Common Practices and Code Improvements, such as merging two if statements with an or, inverting conditions, …
  • Framework-specific inspections for NUnit, ASP.NET, MSBuild, NAnt, JavaScript, Razor, Angular, CSS, …

In this post, we’ve seen how we can learn from Rider’s code analysis. It comes with various inspections that can spot best practices, code improvements and suggest making use of new language features – helping us learn.  In our next post, we’ll look at how Rider can help us maintain a uniform code style, making it easy for new developers to jump into our codebase. Stay tuned!

Download Rider and give it a try! We’d love to hear your feedback.

image description