NDepend

Improve your .NET code quality with NDepend

.NET Micro-Optimization and Refactoring Trick

Recently, I made an interesting observation regarding Dictionary<string,T>: the method TryGetValue() is faster when building  with new Dictionary<string,T>(StringComparer.Ordinal). This performance difference can be attributed to the fact that StringComparer.Ordinal performs a raw byte comparison of string characters. I googled a bit and stumbled on this 2019 runtime note String Dictionary with StringComparer.Ordinal slower than default EqualityComparer.

I updated the benchmark to run against  net7.0, net6.0, net481, net472 (see the benchmark code at the end) and got this result:

Dictionary of string is faster with StringComparer.Ordinal only on .NET Fx platform but slower on .NET Core ones that are so optimized that the default EqualityComparer performs better.

So I built a method to use StringComparer.Ordinal only within .NET Fx context. Let’s precise that most of NDepend code is compiled against netstandard2.0 since it runs within VisualStudio .NET Fx process. But it can also run on a Mac or Linux platform above .NET 5/6/7 and soon 8 (more on this here 5x Lessons Learned from Migrating a Large Legacy to .NET 5/6).

s_Kind is inferred from this trick.

Now all calls to new Dictionary<string,T>() must be refactored into calls to DotNetRuntime.BuildDictionaryOfString<T>().

Refactoring with Resharper Replace with Pattern

Thanks to recent enhancements in Visual Studio 2022 I find myself relying less on Resharper than before. However there is one Resharper awesome feature when it comes to refactoring Replace with Pattern also named Structural Search and Replace. One specific example of its usefulness is when searching for the pattern new Dictionary<string,$T$>() with T being a type expression 99 occurrences of new Dictionary<string,T>() to refactor are matched.

Resharper Search Template

To refactor these occurrences there is a Replace mode in the dialog Change Search Pattern that lets write this Replace pattern: DotNetRuntime.BuildDictionaryOfString<$T$>()

We can see how this feature outperforms a classic textual Find and Replace:

  • It knows about C# and will find expression no matter the formatting (more or less space characters) and comments.
  • Placeholder like $T$ can be provided with a specific meaning. Here $T$ must be a type C# expression, but it could be an identifier, a statement, an argument or an expression.
  • Placeholder can be re-used in the Replace pattern to customize the refactoring.

Click Replace, then the next dialog let’s choose where exactly the refactoring should happen:

Jetbrains Replace Pattern 2

Finally Resharper does the job. However it was not smart enough to import the necessary using statements so I had to do it manually:

Jetbrains Replace Pattern 3

Conclusion

This is a two in one post, with a micro-performance point for those that are still on .NET Framework and a cool Resharper Refactoring tool.

Interestingly enough benchmark shows that HashSet<T> doesn’t run faster with StringComparer.Ordinal.

The Benchmark Code

The C# code:

The .csproj content:

 

My dad being an early programmer in the 70's, I have been fortunate to switch from playing with Lego, to program my own micro-games, when I was still a kid. Since then I never stop programming.

I graduated in Mathematics and Software engineering. After a decade of C++ programming and consultancy, I got interested in the brand new .NET platform in 2002. I had the chance to write the best-seller book (in French) on .NET and C#, published by O'Reilly and also did manage some academic and professional courses on the platform and C#.

Over my consulting years I built an expertise about the architecture, the evolution and the maintenance challenges of large & complex real-world applications. It seemed like the spaghetti & entangled monolithic legacy concerned every sufficiently large team. As a consequence, I got interested in static code analysis and started the project NDepend in 2004.

Nowadays NDepend is a full-fledged Independent Software Vendor (ISV). With more than 12.000 client companies, including many of the Fortune 500 ones, NDepend offers deeper insight and full control on their application to a wide range of professional users around the world.

I live with my wife and our twin kids Léna and Paul in the beautiful island of Mauritius in the Indian Ocean.