This post is part of a series on .NET 6 and C# 10 features. Use the following links to navigate to other articles in the series and build up your .NET 6/C# 10 knowledge! While the articles are seperated into .NET 6 and C# 10 changes, these days the lines are very blurred so don’t read too much into it.
In a previous post, we talked about the coming ability to use global using statements in C# 10. The main benefit being that you were now able to avoid the clutter of declaring namespaces over and over (Things like using System etc) in every single file. I personally think it’s a great feature!
So it only makes sense that when you create a new .NET 6 project, that global usings are implemented right off the bat. After all, if you create a new web project, there are many many files auto generated as part of the template that will call upon things like System or System.IO, and it makes sense to just use GlobalUsings straight away from the start right?
Well… .NET 6 have solved the problem in a different way. With Implicit Using statements, your code will have almost invisible using statements declared globally! Let’s take a look at this new feature, and how it works.
Getting Setup With .NET 6 Preview
At the time of writing, .NET 6 is in preview, and is not currently available in general release. That doesn’t mean it’s hard to set up, it just means that generally you’re not going to have it already installed on your machine if you haven’t already been playing with some of the latest fandangle features.
To get set up using .NET 6, you can go and read out guide here : https://dotnetcoretutorials.com/2021/03/13/getting-setup-with-net-6-preview/
Remember, this feature is *only* available in .NET 6. Not .NET 5, not .NET Core 3.1, or any other version you can think of. 6.
Additionally, there was a change to this feature between .NET 6 Preview and .NET 6 RC. This article has been updated as of 2021-10-07 to reflect what is currently in the very latest SDK version. If you are unsure what you have, go grab the latest SDK just to be sure.
Implicit Global Usings
Implicit Global Usings are an opt in feature (kinda), that is new to .NET 6/C# 10. For existing projects that you are upgrading to .NET 6, you will need to add the following to your csproj file :
However if you create a new project inside Visual Studio 2022 or using the latest SDK from the command line, this flag has already been enabled for you! So again, it’s somewhat opt in, it’s just that you will be opted in by default when creating a new project.
When enabled, implicit usings are actually a hidden auto generated file, inside your obj folder, that declares global using statements behind the scenes. In my case, if I go to my project folder then go obj/Debug/net6.0, I will find a file titled “ProjectName.GlobalUsings.g.cs”.
Opening this file, I can see it contains the following :
global using global::System; global using global::System.Collections.Generic; global using global::System.IO; global using global::System.Linq; global using global::System.Net.Http; global using global::System.Threading; global using global::System.Threading.Tasks;
Note the fact this is an auto generated file, and we can’t actually edit it here. But we can see that it declares a whole heap of global using statements for us.
The project I am demoing this from is actually a console application, but each main project SDK type has their own global imports.
System System.Collections.Generic System.IO System.Linq System.Net.Http System.Threading System.Threading.Tasks
In addition to the console/library namespaces :
System.Net.Http.Json Microsoft.AspNetCore.Builder Microsoft.AspNetCore.Hosting Microsoft.AspNetCore.Http Microsoft.AspNetCore.Routing Microsoft.Extensions.Configuration Microsoft.Extensions.DependencyInjection Microsoft.Extensions.Hosting Microsoft.Extensions.Logging
In addition to the console/library namespaces :
Microsoft.Extensions.Configuration Microsoft.Extensions.DependencyInjection Microsoft.Extensions.Hosting Microsoft.Extensions.Logging
Of course, if you are unsure, you can always quickly create a project of a certain type and check the obj folder for what’s inside.
If we try and import a namespace that previously appeared in our implicit global usings, we will get the usual warning.
As previously mentioned, if you are creating a brand new .NET 6 and C# 10 (Which in a years time, the majority will be), then this feature is turned on by default. I have my own thoughts on that, but what if you want to turn this off? This might be especially common when an automatically imported namespace has a type that conflicts with a type you yourself are wanting to declare. Or what if you just don’t like the hidden magic full stop?
Well of course we can either delete the flag all together, or set it to be disabled if we want to be a bit more explicit :
Note that clearly, if we switch this flag to disabled on a live project that’s been going for some time, you’re likely to get 100’s of errors due to a project not importing the correct namespaces.
There is also another option to selectively remove (and add) implicit namespaces like so :
<ItemGroup> <Using Remove="System.Threading" /> <Using Include="Microsoft.Extensions.Logging" /> </ItemGroup>
Here we are removing System.Threading and adding Microsoft.Extensions.Logging to the global implicit using imports.
This can also be used as an alternative to using something like a GlobalUsings.cs file in your project of course, but it is a somewhat “hidden” feature.
Is This A Good Feature? / My Thoughts
In the original version of this article, I was mostly down on this feature. And that’s saying something because I rarely comment on new features being good or bad. Mostly it’s because I presume that people much smarter than I know what they are doing, and I’ll get used to it. I’m sure when things like generics, lambdas, async/await got introduced, I would have been saying “I don’t get this”.
On the surface, I like the idea of project types having some sort of implicit namespace. Even imports that I thought were kinda dumb to be global such as “System.Threading.Tasks”, I soon realized are needed in every single file if you are using async/await since your methods must return a type of Task.
Originally, Implicit Usings were enabled by default *without* a flag in the csproj, and instead you had to add something like so to disable them :
The new version is better, in that we are opted in explicitly, but still the “hiddenness” of it all isn’t so great. I don’t like the idea of files being auto generated in the obj folder because for the most part, people do not go and look there. If you are doing a Ctrl + Shift + F inside your project to find a pesky namespace clash, you’re not going to find your auto generated implicit usings file.
I feel like a simpler idea would have been to edit the Visual Studio/Command Line templates that when you create a new web project, it automatically creates a GlobalUsings.cs file in the root of the project with the covered implicit namespaces already in there. To me, that would be a heck of a lot more visible, and wouldn’t lead to so much confusion over where these hidden imports were coming from.
That being said, maybe in a years time we just get used to it and it’s just “part of .NET” like so many other things. What’s your thoughts?