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)
- Introduction to code analysis in Rider
- Solution-wide analysis in Rider
- Using Rider to spot errors before our application runs
- Learning best practices and language features using Rider code inspections
- Consistent code bases using Rider code analysis
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
var range = Enumerable.Range(1, 100);
foreach (var element in range)
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:
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):
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:
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:
<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.
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):
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:
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
forloop into a
- 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, …
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.