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 - no need to pick arbitrary type arguments
string listName = nameof(List<>); // "List"
string dictName = nameof(Dictionary<,>); // "Dictionary"
// Useful for logging and diagnostics
Console.WriteLine($"Registering {nameof(List<>)} handler");
// Works with custom generic types
class MyGeneric<T, U> { }
string myName = nameof(MyGeneric<,>); // "MyGeneric"C#
// Had to specify arbitrary type arguments even though they were irrelevant
string listName = nameof(List<int>); // "List"
string dictName = nameof(Dictionary<int, string>); // "Dictionary"
// Misleading - suggests a dependency on those specific types
Console.WriteLine($"Registering {nameof(List<int>)} handler");
// 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. - Returns the simple name without arity suffix, same as the bound form (e.g. both
nameof(List<>)andnameof(List<int>)return"List") - Aligns
nameofsyntax withtypeofwhich already accepted unbound generic types - Avoids misleading code that specifies arbitrary type arguments just to satisfy the compiler