Skip to content

Unbound generic types and `nameof` C# 14.0correctness

Use the `nameof` keyword with generic definitions.

The nameof operator C# 6.0 previously could only be used with generic types when all type arguments were specified. This meant you couldn't get the name of a generic type definition itself without providing type arguments, even when you didn't care about the specific type.

C# 14.0 allows nameof to work with unbound generic types using the <> syntax, making it possible to get the name of generic type definitions without needing to specify type arguments.

Code

C#
// Works with unbound generic types
string listName = nameof(List<>);              // "List`1"
string dictName = nameof(Dictionary<,>);       // "Dictionary`2"
string funcName = nameof(Func<,,,>);           // "Func`4"

// Useful for reflection and logging
Type listType = typeof(List<>);
string name = nameof(List<>);
Console.WriteLine($"Working with {name}");

// Works with custom generic types
class MyGeneric<T, U> { }
string myName = nameof(MyGeneric<,>);          // "MyGeneric`2"
C#
// Had to specify type arguments even when arbitrary
string listName = nameof(List<int>);           // "List"
string dictName = nameof(Dictionary<int, string>); // "Dictionary"
string funcName = nameof(Func<int, int, int, int>); // "Func"

// Or use typeof with .Name
string name = typeof(List<>).Name;             // "List`1"
Console.WriteLine($"Working with {name}");

// Same issue with custom types
class MyGeneric<T, U> { }
string myName = nameof(MyGeneric<int, string>); // "MyGeneric"

Notes

  • Use <> for single type parameter, <,> for two, <,,> for three, etc.
  • The result includes the backtick notation (e.g., List1`) that indicates the number of type parameters
  • This aligns nameof behavior with typeof for unbound generic types
  • Particularly useful in generic code, reflection scenarios, and logging frameworks
  • The number of commas matches the number of type parameters minus one

More information