I am a constant learner and as a part of that effort I try and read one thing each day. Hopefully you will find this information useful.
Quality Issue #1 – Count vs. Count()
A measure of how good you are as a developer is how well you can write code. This is a start of a series of posts to help developers write better code. Today we will look at Count vs. Count() in .NET.
Count
There are many collections in .NET that support a property called Count. This includes List, List<T>, HashSet<T>, and many more. The Count property is a value the represents the number of elements in the collection.
Here is the documentation for the List<T>.Count property.
List<T>.Count Property (System.Collections.Generic) | Microsoft Docs
Count()
.NET supports two interfaces, IEnumerable and IEnumerable<T>, which provide the ability to iterate over a collection. Along with these interfaces are a set of static extension methods defined in Enumerable which add functionality for querying a collection of objects based on LINQ. One of those methods is Count() which iterates over the collection to determine the number of items in the collection.
Here is the documentation for the IEnumerable interface and Enumerable.Count method.
IEnumerable Interface (System.Collections) | Microsoft Docs
IEnumerable<T> Interface (System.Collections.Generic) | Microsoft Docs
Enumerable.Count Method (System.Linq) | Microsoft Docs
Comparison
So why do we care about the difference between Count and Count()? One simply reads a value in memory to determine the count of the elements in a collection and the other iterates over the entire collection in memory to determine the count of the number of items.
There is a big performance difference when it comes to these two approaches. What is worse is that the performance difference gets worse when the size of the collection grows. These might now seem like a big deal, but it does add up over time. If you have a large code base or high scale application, you will begin to see the impact over time.
Here is an example of code that gets a collection of people using List<Person>. We then use Count and Count() to get the number of people in the collection.
We measure the performance difference between the two approaches. One can see that Count() extension method takes 7 times longer than using the Count property. This gets worse when the number of items in the collection increases.
If you don’t believe that this is a quality issue, check out the code analysis tip in Visual Studio by hovering over the Count() method. There you will see code analysis rule CA1829.
The description of rule CA1829 provides a clear reason as to why not to use the Count() method.
“The Count LINQ method was used on a type that supports an equivalent, more efficient Length or Count property.”
Here is the documentation for the Code Analysis Performance Rule CA1829.
Anecdote
I remember being one of a four architects on Fidelity’s Active Trader Pro. This is amazing product put together by about 80 to 90 awesome developers. Count vs. Count() was one of the performance problems we would find in our code reviews. An even bigger challenge was the overuse of LINQ queries in a fluent style programming syntax. Finding bad LINQ queries was a large part of our performance optimization during the project. This leads me to one of my favorite things to tell developers, “LINQ is convenient not performant”. Interestingly, I am on a project at the moment where we are addressing quality issues such as Count vs. Count().
Conclusion
It is out hope that you have learned the proper the use of Count vs. Count() and that this is the beginning of your journey to improve the quality of the code that you write.
Appreciation
Thanks to our friends at MILL5 for sponsoring this article.
Author(s):
Richard Crane, Founder/CTO
Disclaimer:
All source code is licensed under the Apache 2.0 license.
References:
Count vs. Count() Code Example
https://github.com/MILL5/quality/tree/main/fundamentals/Count
Working with Azure Maps
So we are doing a bunch of projects with Azure Maps. Azure Maps is relatively new. Fortunately, the Azure Maps team at Microsoft provided 114 samples to get people started. Click here for Azure Maps samples
Daily Update – Oh Yeah! Use UserName Instead of Email Address with Docker
Every time I have to do docker work, I forget that Docker for Windows needs to authenticate using your Docker Hub “username” and not your “email address”. This is so confusing because Docker Hub will allow you to use your email address when you visit the website and from the tray application in Docker for Windows.
When you use your email address to authenticate with docker it creates all sort of problems with Docker for Windows and Visual Studio. Running docker login from the Command Prompt shows the issue. If you use your email address, it works fine on hub.docker.com and from the tray application, but you will experience issues with docker login and Visual Studio. The issues include failed deployments, failing to start docker, failing to authenticate, and more. All of these errors are almost random. You can even get into a bad state where you feel that you have to reset docker.
Daily Learning – Ugh! Guids As Primary Keys
I am working on fixing a database that uses GUIDs (i.e. uniqueidentifier) as primary keys. Our customer does a high number of inserts and generates their keys from their application or from NEWID(). In addition, their primary keys are clustered. There are many articles on the Internet that talk about the problem of using non-sequential GUIDs as primary keys. Kimberly Tripp over at SQLSkills has a good article here. The short description of the problem is that generating a non-sequential key can create fragmentation. Unless you use a function that generates sequential GUIDs, like NEWSEQUENTIALID, you are bound to see fragmentation. Additionally, a GUID is an unnecessarily wide key and can bloat your non-clustered indexes and add significant overhead in terms of wasted space and query performance.
I love GUIDs as keys, but not primary keys. In order to fix this problem, I created a database generated identifier (i.e. IDENTITY) as the primary key with an integer (i.e. int) data type. I then create a unique index on the original GUID which gives me the benefit of having the best of both worlds. First, a small, sequential identifier that is highly optimized for querying, joins, and storage. And second, a globally unique identifier which I can share outside my application.
NOTE: We see this problem all the time. That is what happens when you have developers manage your database.
Daily Learning – Adding a global filter for authorization in ASP.NET Core
First, let me say that we love IdentityServer4. It doesn’t hurt that we have been using IdentityServer since its early days or that Brock Allen is a good friend of ours. We are doing some IdentityServer work for our customers and I needed to create a sample application that requires authentication for all pages. After some digging around, I found that we can add a global filter for authorization. Neat!
Daily Learning – Paintbrush for Mac OS X a simple replacement for Paint.NET
One of the most useful tools for Windows is Paint.NET. Apple had created their version of a simple paint application many years ago but has since abandoned it. I wanted to get one for my Mac and after a quick search came across Paintbrush.
Paintbrush – The Bitmap Image Editor for Mac OS X
https://paintbrush.sourceforge.io/
Daily Learning – Injecting configuration for your ASP.NET Core application
We are building a product from scratch. As such we are running into minor issues just getting everything set up when we are creating the code. Interestingly I was having an issue accessing my configuration. Originally I had just put the property on the class forgetting that I needed to define a constructor so that the configuration would be injected. Good on you Microsoft sticking to constructor injection!
Daily Learning – Checking which version of .NET Core is installed
Recently I had an issue where I did not have the latest version of .NET Core installed. To check which versions I had installed I used the following command: