C#idiomatic C#
generics-and-attributescsharp/advanced-topics/reflection-and-attributes

Advanced

Generics and Attributes

Learn about applying attributes to generic types. See code examples and view more available resources.

  • page csharp/advanced-topics/reflection-and-attributes/generics-and-attributes
  • updated 11/18/2025

Attributes can be applied to generic types in the same way as nongeneric types. However, you can apply attributes only on open generic types and closed constructed generic types, not on partially constructed generic types. An open generic type is one where none of the type arguments are specified, such as Dictionary<TKey, TValue> A closed constructed generic type specifies all type arguments, such as Dictionary<string, object>. A partially constructed generic type specifies some, but not all, type arguments. An example is Dictionary<string, TValue>. An unbound generic type is one where type arguments are omitted, such as Dictionary<,>.

The following examples use this custom attribute:

sample · csharpdocs/csharp/advanced-topics/reflection-and-attributes/snippets/conceptual/GenericsAndAttributes.csCustomAttribute

csharp

namespace GenericsExamples;

//<CustomAttribute>
class CustomAttribute : Attribute
{
    public object? info;
}
//</CustomAttribute>

//<GenericClassAsAttribute>
public class GenericClass1<T> { }

[CustomAttribute(info = typeof(GenericClass1<>))]
class ClassA { }
//</GenericClassAsAttribute>

//<TypeParameters>
public class GenericClass2<T, U> { }

[CustomAttribute(info = typeof(GenericClass2<,>))]
class ClassB { }
//</TypeParameters>

//<ClosedGeneric>
public class GenericClass3<T, U, V> { }

[CustomAttribute(info = typeof(GenericClass3<int, double, string>))]
class ClassC { }
//</ClosedGeneric>

//<GenericAttribute>
public class CustomGenericAttribute<T> : Attribute { }
//</GenericAttribute>

An attribute can reference an unbound generic type:

sample · csharpdocs/csharp/advanced-topics/reflection-and-attributes/snippets/conceptual/GenericsAndAttributes.csGenericClassAsAttribute

csharp

namespace GenericsExamples;

//<CustomAttribute>
class CustomAttribute : Attribute
{
    public object? info;
}
//</CustomAttribute>

//<GenericClassAsAttribute>
public class GenericClass1<T> { }

[CustomAttribute(info = typeof(GenericClass1<>))]
class ClassA { }
//</GenericClassAsAttribute>

//<TypeParameters>
public class GenericClass2<T, U> { }

[CustomAttribute(info = typeof(GenericClass2<,>))]
class ClassB { }
//</TypeParameters>

//<ClosedGeneric>
public class GenericClass3<T, U, V> { }

[CustomAttribute(info = typeof(GenericClass3<int, double, string>))]
class ClassC { }
//</ClosedGeneric>

//<GenericAttribute>
public class CustomGenericAttribute<T> : Attribute { }
//</GenericAttribute>

Specify multiple type parameters using the appropriate number of commas. In this example, GenericClass2 has two type parameters:

sample · csharpdocs/csharp/advanced-topics/reflection-and-attributes/snippets/conceptual/GenericsAndAttributes.csTypeParameters

csharp

namespace GenericsExamples;

//<CustomAttribute>
class CustomAttribute : Attribute
{
    public object? info;
}
//</CustomAttribute>

//<GenericClassAsAttribute>
public class GenericClass1<T> { }

[CustomAttribute(info = typeof(GenericClass1<>))]
class ClassA { }
//</GenericClassAsAttribute>

//<TypeParameters>
public class GenericClass2<T, U> { }

[CustomAttribute(info = typeof(GenericClass2<,>))]
class ClassB { }
//</TypeParameters>

//<ClosedGeneric>
public class GenericClass3<T, U, V> { }

[CustomAttribute(info = typeof(GenericClass3<int, double, string>))]
class ClassC { }
//</ClosedGeneric>

//<GenericAttribute>
public class CustomGenericAttribute<T> : Attribute { }
//</GenericAttribute>

An attribute can reference a closed constructed generic type:

sample · csharpdocs/csharp/advanced-topics/reflection-and-attributes/snippets/conceptual/GenericsAndAttributes.csClosedGeneric

csharp

namespace GenericsExamples;

//<CustomAttribute>
class CustomAttribute : Attribute
{
    public object? info;
}
//</CustomAttribute>

//<GenericClassAsAttribute>
public class GenericClass1<T> { }

[CustomAttribute(info = typeof(GenericClass1<>))]
class ClassA { }
//</GenericClassAsAttribute>

//<TypeParameters>
public class GenericClass2<T, U> { }

[CustomAttribute(info = typeof(GenericClass2<,>))]
class ClassB { }
//</TypeParameters>

//<ClosedGeneric>
public class GenericClass3<T, U, V> { }

[CustomAttribute(info = typeof(GenericClass3<int, double, string>))]
class ClassC { }
//</ClosedGeneric>

//<GenericAttribute>
public class CustomGenericAttribute<T> : Attribute { }
//</GenericAttribute>

An attribute that references a generic type parameter causes a compile-time error:

csharp
[CustomAttribute(info = typeof(GenericClass3<int, T, string>))]  //Error CS0416
class ClassD<T> { }

A generic type can inherit from System.Attribute:

sample · csharpdocs/csharp/advanced-topics/reflection-and-attributes/snippets/conceptual/GenericsAndAttributes.csGenericAttribute

csharp

namespace GenericsExamples;

//<CustomAttribute>
class CustomAttribute : Attribute
{
    public object? info;
}
//</CustomAttribute>

//<GenericClassAsAttribute>
public class GenericClass1<T> { }

[CustomAttribute(info = typeof(GenericClass1<>))]
class ClassA { }
//</GenericClassAsAttribute>

//<TypeParameters>
public class GenericClass2<T, U> { }

[CustomAttribute(info = typeof(GenericClass2<,>))]
class ClassB { }
//</TypeParameters>

//<ClosedGeneric>
public class GenericClass3<T, U, V> { }

[CustomAttribute(info = typeof(GenericClass3<int, double, string>))]
class ClassC { }
//</ClosedGeneric>

//<GenericAttribute>
public class CustomGenericAttribute<T> : Attribute { }
//</GenericAttribute>

To obtain information about a generic type or type parameter at run time, you can use the methods of System.Reflection. For more information, see Generics and Reflection.

See also