The Problem with C# 10 Implicit Usings

Microsoft .NET

Update (2021-10-14)

Mark Rendle made an interesting suggestion on Twitter after seeing this blog post. I've updated the post below with his code.

Yesterday I livestreamed myself upgrading a project to .NET 6 and C# 10. Along the way I tried using a new C# 10 feature called implicit using statements and discovered that it wasn't quite as straightforward as I first thought and you should probably not use it under certain circumstances.

Here is the live stream for those who are interested (I'm eager to get any feedback on how I'm presenting as its not a natural skill for me):

What are Implicit Using Statements?

Adding the line below to your .csproj project file turns the feature on:

<ImplicitUsings>enable</ImplicitUsings>

Once enabled, depending on the type of project you have created you'll have the following global using statements added to your project implicitly.

SDKDefault namespaces
Microsoft.NET.SdkSystem
System.Collections.Generic
System.IO
System.Linq
System.Net.Http
System.Threading
System.Threading.Tasks
Microsoft.NET.Sdk.WebSystem.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
Microsoft.NET.Sdk.WorkerMicrosoft.Extensions.Configuration
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Hosting
Microsoft.Extensions.Logging

Sounds great, now you can delete a large portion of the using statements in your project right? Well not so fast, here are some problems I discovered along the way.

Build Errors

I discovered the first problem while multi-targetting a class library project for a NuGet package. I had targetted .NET 4.7.2 as well as other target frameworks like .NET 6 for backwards compatibility and found that System.Net.Http could not be found. It turns out I hadn't referenced that particular NuGet package for .NET 4.7.2 and was now getting a build error.

I could add the System.Net.Http NuGet package for .NET 4.7.2 on its own and that would solve the problem but I really didn't like having the overhead of another unnecessary package reference. That also means extra work for me to maintain updating the version number or relying on tools like Dependabot and Renovate to submit PR's to upgrade the version number for me.

<ItemGroup Label="Package References (.NET 4.7.2)" Condition="'$(TargetFramework)' == 'net472'">
    <PackageReference Include="System.Net.Http" Version="4.3.4" />
</ItemGroup>

Mark Rendle on Twitter suggested another workaround after seeing this blog post. His suggestion was to remove the offending using statement in the .csproj file.

<ItemGroup>
    <Using Remove="System.Net.Http" />
</ItemGroup>

This looks awfully strange to me. I'm not sure how I feel about adding or removing namespaces from C# project files yet. It doesn't seem very discoverable to me. So in this particular case I'm happy to avoid using implicit using statements for now.

What Using's Were Added?

The second problem is trying to understand what using's have been added. As you can see from the table above, you could go and look in the documentation to figure this out but that's slow and time consuming. Another alternative is actually to build your project and then look in its obj directory under:

My.Project\obj\Debug\net472\My.Project.GlobalUsings.g.cs

That's not ideal either. I think Visual Studio should ideally show you these using statements somehow.

Conclusions

Implicit usings are enabled by default in the latest blank project templates shipped with .NET. Overall this is a cool feature that can remove the need for many duplicated lines of code in your project but I think there is a little too much magic going on here for my liking, so I think I'll be more careful about using this feature in the future.

Web Mentions

What's this?

0 Replies

GitHub Comments

sam-wheat

Another problem with implicit global usings is that because .net creates the globalusings file in the obj folder it does not create a file that you can modify as part of your project. I think the correct behavior should be that .net creates a file for you that you can modify . Also, if you use VS intellisense to add a using statement it adds the using to the current file only. If you are using a GlobalUsings.cs file the using... statement will be added to the wrong file.

teo-tsirpanis

You shouldn't use the System.Net.Http NuGet package, it's super old. Instead you should add a <Reference Include="System.Net.Http" /> item in your project; that references the built-in assembly in the framework.

XtroTheArctic

Can you please make the font of your blog website even bigger so it becomes totally unreadable instead of being partially unreadable?

XtroTheArctic

Fair enough! I was joking you know. But still, your font is too big compared to the Internet standards :)

XtroTheArctic

Oh I just noticed your social buttons don't work. Just in case you want to fix them.
image

XtroTheArctic

Originally, I was commenting on @RehanSaeed's blog website. Here is its big font size compared to CNN's text size which is also kinda big:
image

After you @sam-wheat joined the conversation, I checked your sites too:
image
image