Back to Blog
C#

C# Using Alias for Generic Types

Learn how C# using aliases shorten closed generic type names, why open generic types cannot be aliased, and when a wrapper class may be a better fit.

C#type aliasesgeneric typescode readabilityusing directive
C# code showing a using alias for a generic type being declared and used

When a generic type name grows long, it becomes harder to read and maintain. A using alias lets you assign a shorter name to a closed generic type, such as Dictionary<string, List<int>>, and then use that alias throughout the file. This is a compile-time feature: the alias is resolved to the full type during compilation and has no runtime cost.

The general syntax is:

using AliasName = Fully.Qualified.GenericType<TypeArguments>;

You place the directive at the top of a file or inside a namespace block, before type declarations. After that, AliasName can be used wherever the full type name would appear.

Declaring a Using Alias for a Closed Generic Type

A closed generic type has all of its type parameters specified. For example, List<string> is closed, while List<T> is open. You can alias a closed generic type like this:

using StringList = System.Collections.Generic.List<string>; using StringDictionary = System.Collections.Generic.Dictionary<string, string>;

Once declared, you can use these aliases as if they were the original type:

StringList names = new StringList { "Ada", "Grace" }; StringDictionary map = new StringDictionary { ["key"] = "value" };

The alias is not a new type. It is an alternative name for the same underlying type. You can assign between the alias and the original type without any conversion:

List<string> list = new StringList(); StringList anotherList = list;

Both variables refer to the same type, so the assignment works directly.

Why You Cannot Alias an Open Generic Type

An open generic type has one or more type parameters that are not specified. The using directive cannot alias an open generic type, and it also cannot alias an unbound generic type definition such as List<>. You cannot write:

using MyList = System.Collections.Generic.List<>; // Compiler error

You also cannot alias a form like List<T>. The alias would need to be generic itself, and the using directive does not support generic parameters.

If you need a shorthand that still accepts type arguments, a generic wrapper class can help, though it changes the type identity. A helper factory method can also reduce repetitive construction, but it is not a type alias.

For most practical purposes, you alias a specific constructed type. If you find yourself repeatedly writing List<SomeVeryLongClassName> and want to shorten it, you can alias that exact combination.

Practical Example: Simplifying Nested Generic Types

Nested generic types are common in real code. Consider a dictionary that maps a string key to a list of integer values:

Dictionary<string, List<int>> lookup = new Dictionary<string, List<int>>();

Writing this type repeatedly becomes tedious. An alias reduces the noise:

using LookupTable = System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<int>>; LookupTable lookup = new LookupTable();

Now the variable declaration and any method signatures that use this type are shorter and clearer. This is especially useful when the type appears in multiple places, such as method parameters, return types, or field declarations.

Scope, File-Level Behavior, and Global Aliases

A using alias follows the same scoping rules as a namespace using directive. Placed outside any namespace, it applies to the whole compilation unit (normally a file); placed inside a namespace block, it applies only within that block. It does not affect other files unless you also declare the same alias there. The alias must appear before any type declarations, either at the top of the file or inside a namespace block. It cannot be placed inside a method or class body.

Before C# 10, this behavior meant you had to repeat an alias in every file that needed it. In C# 10 and later, you can declare a project-wide alias with global using:

global using StringList = System.Collections.Generic.List<string>;

A global using alias is typically placed in a dedicated file such as GlobalUsings.cs. Like other aliases, a global alias for a generic type must name a closed generic type.

Consistent use within a file helps readability. If a long type name appears only once, an alias may not be worth the extra line. If it appears several times, the alias improves readability and reduces the chance of typos.

Maintainability Considerations

Using aliases can improve maintainability when a type name is verbose, but they also introduce an indirection. A reader must know what the alias refers to. If the alias is not descriptive, it can obscure the underlying type. Choose alias names that convey the purpose of the type, not just a shortened version of the full name.

For example, using UserCache = System.Collections.Concurrent.ConcurrentDictionary<string, User>; is more meaningful than using CD = System.Collections.Concurrent.ConcurrentDictionary<string, User>;. The alias should make the code easier to understand, not harder.

Another consideration is that changing the underlying type later requires updating the alias definition, which is usually easier than updating every usage. However, if you change the alias to a different type, the code that uses it may break if the new type has a different API. Aliases do not provide a layer of abstraction; they are purely syntactic sugar.

When to Prefer a Wrapper Class Over an Alias

A using alias is not a new type. It cannot add methods, properties, or behavior. If you need to extend a generic type with custom functionality, a wrapper class is more appropriate. For example, you might create a class that inherits from List<T> or contains a List<T> internally and exposes specific methods.

A wrapper class also allows you to define a reusable generic name that still accepts type parameters. You could write:

public class MyList<T> : List<T> { }

Then MyList<int> is a distinct type that behaves like List<int>. This changes the type identity, so it is not a purely compile-time convenience. Use it when you need behavior beyond what an alias provides.

For most cases where you simply want a shorter name for a closed generic type, a using alias is the cleanest solution. It keeps the type identity intact and adds no runtime overhead.

C# Using Alias for Generic Types: Syntax, Scope, and Examples | RYUSLOG DEV