I'll be talking about the versatile using directive in C# - its various usages, the subtle differences of placing it inside vs. outside of the namespace, and other related things. So, let's begin.

1. The Basic using Directive

Before we go into the complexities, let's review the basics. The using directive is primarily used for including namespaces, which helps avoid specifying the full namespace path every time you access a class or member.

using System;
using System.Collections.Generic;

// You can now use List<T> without specifying its full path.
List<int> numbers = new List<int>();

2. Inside vs. Outside Namespaces

You might've seen using directives placed both inside and outside namespaces. Does the location matter? Absolutely!

  • Outside Namespaces: The most common usage. It makes the specified namespaces available to all the code in the file.
  • Inside Namespaces: This restricts the scope of the using directive to only that namespace. This can help avoid ambiguity if there are identically named types across different namespaces in the same file. For those curious, I personally lean towards this approach.
using System; // Global to the file

namespace A {
    using System.Collections.Generic; // Specific to namespace A
    ...
}

namespace B {
    // Doesn't have access to System.Collections.Generic from namespace A
    ...
}

This practice can be useful in larger projects where managing dependencies becomes crucial.


3. using Aliases

In cases where there's a naming conflict or when you want to give a type a more meaningful or shorter name, you can use using to create an alias:

using StringCollection = System.Collections.Specialized.StringCollection;

With this alias in place, you can use StringCollection instead of its full namespace path.


4. Static using Directive

C# 6 introduced the static using directive, which allows you to access static members of a type without specifying the type name:

using static System.Math;

double radius = 10.0;
double area = PI * Pow(radius, 2); // No need to prefix with Math.

5. Using Directives for Additional Types in C# 12

New capabilities are coming for the using directive in the upcoming version 12 of the C# language. Now, the using directive has been extended to support almost any type. This means you're not restricted to just namespaces or specific classes anymore!

Examples:

using Measurement = (string, int);
using PathOfPoints = int[];
using DatabaseInt = int?;

Tuples: Particularly exciting is the support for tuples. You can now alias them with both element names and types.

using Measurement = (string Units, int Distance);

You can read more about it on the Microsoft dev blog. I don't see why you would do this instead of creating a separate class, but you have the option to use it this way!


Is this all you've got!?

Absolutely not!

The term using in C# can be both a keyword and a directive, depending on its context:

  1. Directive: When used at the top of a C# file, using is a directive that allows you to import namespaces or create type aliases, e.g., using System; or using StringCollection = System.Collections.Specialized.StringCollection;.
  2. Keyword: When used in the context of resource management, it's a keyword. It denotes a statement in C# that provides a convenient syntax to ensure that an object implementing IDisposable is correctly disposed of. Read more about IDisposable, managed and unmanaged resources in the previous newsletter.

The using statement for Resource Management

Before C# 8, the using statement was widely used for resource management, especially for objects holding unmanaged resources. It made sure that the object's Dispose method was called once the object was no longer needed.

Here's an example:

using (StreamWriter writer = new StreamWriter("file.txt"))
{
    writer.Write("Hello, world!");
}

Under the hood

The using statement translates to a try-finally block. The previous example becomes something similar to:

StreamWriter writer = new StreamWriter("file.txt");

try
{
    writer.Write("Hello, world!");
}
finally
{
    writer?.Dispose();
}

This ensures that even if an exception occurs within the scope of the using statement, the Dispose method is always called during the cleanup in the finally block.

C# 8's "using" declaration

The C# 8 introduced the using declaration, a more succinct way to ensure the disposal of resources. The object will be disposed of at the end of the containing scope.

using var writer = new StreamWriter("file.txt");
writer.Write("Hello, world!");
// writer is disposed of at the end of the current scope.

Does it only work with IDisposable?

Yes, the using statement or declaration works specifically with classes that implement the IDisposable interface. This interface contains just one method, Dispose, which is meant to release all the resources, especially unmanaged resources. If you try to use the using statement on a type that does not implement IDisposable, you'll get a compile-time error telling you that "Type used in a using statement must be implicitly convertible to 'System.IDisposable'".

Quick Tips & Best Practices:

  • Limit Alias Usage: While aliases can be handy, overusing them can make code harder to understand for others. Use them sparingly and only when necessary.
  • Organize & Group: If you have multiple using directives, group them by purpose or library. This makes it easier to spot related dependencies.
  • Clean Up: Use tools like ReSharper or Visual Studio's built-in features to remove unnecessary using directives, keeping your codebase clean.

If you prefer to keep your using directives within the namespace, as I do, but you don't have a ReSharper to do it automatically. Fear not! Since Visual Studio 2019 update 16.1, you can do so automatically with just Visual Studio without additional extensions. I shared this tip with the StackOverflow community a long time ago.

  1. Open Visual Studio
  2. In the toolbar, go to Tools
  3. Within the Tools menu, open Options
  4. In the options list, select Text Editor > C# > Code Style > General
  5. Scroll down near the bottom, find the 'using' preferences section, and set the Preferred 'using' directive placement to Inside namespace
enter image description here

And if you want to enforce the same thing through your .editorconfig file, add the following in there:

csharp_using_directive_placement = inside_namespace:suggestion

Conclusion

The using directive offers many utility features that can make your C# coding experience smoother and more efficient. Whether resolving naming conflicts, simplifying access to static members, or ensuring resources are cleaned up, using is used a lot in the C# language.