In this article, we’re going to learn about the using static directive feature in C#.
Let’s dive in.
What Is a “using static” Directive?
In C# 6, the using static
directive was introduced to reduce the boilerplate code when accessing the static members of a type:
using static <fully-qualified-type-name>;
Once we name a type with the using static
directive, we can reference the static members and nested types of the <fully-qualified-type-name>
without using its name.
Let’s look at how we can access the different types of static members with the using static
directive.
Methods and Properties
Let’s create a sample class ClassA
with two static methods MethodA()
and MethodB()
:
public static class ClassA { public static void MethodA() { } public static void MethodB() { } }
In order to invoke these methods, we usually call them by their class name:
ClassA.MethodA(); ClassA.MethodB();
Here, we’re repeating the class name ClassA
for invoking its static members every time. If we have to call the static members in many places, then the codebase will become too verbose.
But, with this feature, we can directly call the static methods without using their class name every time.
For that, we first need to name the type ClassA
with the using static
directive:
using static ClassA; MethodA(); MethodB();
After that, we can directly call the static methods MethodA()
and MethodB()
. Similarly, we can access the static properties and fields.
Enums
Accessing the enum items directly without using the enum type name is also possible. Let’s create an enum Role
with two items User
and Admin
:
public enum Role { User, Admin }
Usually, we would’ve accessed the enum items by their type name:
Role role = Role.User;
If we’re about to use the enum items in multiple places, then we can import the items with using static Role
:
using static Role; Role role = User;
Now, we can refer to the enum item User
or any other without using its enum name.
Constants
In the same way, we can also directly access the constants. Let’s create a class Status
with a few constants:
public class Status { public const string Pending = "Pending"; public const string InProgress = "InProgress"; public const string Completed = "Completed"; }
To access these constants, we first need to name the type Status
with the using static
directive:
using static Status;
And then, we can directly access the constants Pending
, Completed
:
var pending = Pending; var completed = Completed;
Nested Type Members
We can call the nested type’s static members in a similar way. Let’s create the nested type ClassB
within ClassA
. The nested type has two methods MethodA()
and MethodB()
:
public class ClassA { public class ClassB { public static void MethodA() { } public static void MethodB() { } } }
In order to call these methods, we usually end up calling them by prefixing the entire nested class hierarchy:
ClassA.ClassB.MethodA(); ClassA.ClassB.MethodB();
We can see that it is too verbose as we are repeating ClassA.ClassB
every time to invoke the methods MethodA()
and MethodB()
of the nested class.
To overcome this, we can import the nested type members by the using static
feature and call them directly. In order to do so, we first need to name the nested type ClassA.ClassB
with the using static
directive:
using static ClassA.ClassB; MethodA(); MethodB();
After that, we can call the methods MethodA()
and MethodB()
directly.
Or else, we can only name the ClassA
with using static
directive and then access the ClassB
methods as ClassB.MethodA()
and ClassB.MethodB()
:
using static ClassA; ClassB.MethodA(); ClassB.MethodB();
Extension Methods
Extension methods are available for lookup if they are anywhere in the same namespace. But if it’s in a different namespace, we can name its type with the using static
directive and start using the extension methods.
Let’s create a static class NumberExtensions
with an extension method Add()
that will add two numbers in NamespaceA
:
namespace NamespaceA; public static class NumberExtensions { public static int Add(this int number1, int number2) { return number1 + number2; } }
Once, we name the class NumberExtentions
with the using static
directive, then the extension method Add()
is available for lookup on its type int
in NamespaceB
:
using static NamespaceA.NumberExtensions; namespace NamespaceB; var sum = 1.Add(2);
But it’s not possible to invoke it like a regular method using this feature:
NumberExtensions.Add(1, 1); // Valid // Error CS0103 // The name 'Add' does not exist in the current context Add(1, 1);
NumberExtensions.Add()
is a valid method call when called by its class name. However, it’s not possible to call the Add()
method directly by using the using static
directive. This applies only to extension methods.
Base Class Members
Using this feature, we cannot import the base class’s static members. Let’s create a base class ClassA
with one static member MethodA()
and a derived class ClassB
with a static method MethodB()
:
public class ClassA { public static void MethodA() { } } public class ClassB : ClassA { public static void MethodB() { } }
After importing the static members of ClassB
, we can call the MethodB()
without any errors.
But, if we try to call the base class method MethodA()
, we get a compiler error:
using static ClassB; // Valid MethodB(); // Error CS0103 // The name 'MethodA' does not exist in the current context MethodA();
Ambiguity Considerations With “using static” Directive
If we import static members of two different types with using static
, we need to ensure that the method signatures are unique among those types. Otherwise, the compiler will throw an error if we try to access the method with the same signature.
Let’s create two classes ClassA
and ClassB
with the same method signature void Method()
:
public class ClassA { public static void Method() { } } public class ClassB { public static void Method() { } }
If we call this method when two of these classes are named with using static
directive, then compile time error will be thrown:
using static ClassA; using static ClassB; // Error CS0121 // The call is ambiguous between the following methods or properties: 'ClassA.Method()' and 'ClassB.Method()' Method();
Hence, we need to ensure that the method signatures are unique among the imported types.
Conclusion
In this article, we’ve learned all about using static directive and their usage. This is a great feature and comes in handy when we want to reduce the verbosity of the frequently accessed static members.