特性可按与非泛型类型相同的方式应用到泛型类型。 但是,只能将特性应用于开放式泛型类型和封闭式构造泛型类型,而不能应用于部分构造泛型类型。 开放式泛型类型是未指定任何类型参数的类型,例如 Dictionary<TKey, TValue>;封闭式构造泛型类型指定所有类型参数,例如 Dictionary<string, object>。 部分构造泛型类型指定一些(而非全部)类型参数。 示例为 Dictionary<string, TValue>。 未绑定泛型类型是省略类型参数的泛型类型,例如Dictionary<,>。
泛型和特性
以下示例使用此自定义属性:
class CustomAttribute : Attribute
{
public object? info;
}
属性可以引用未绑定的泛型类型:
public class GenericClass1<T> { }
[CustomAttribute(info = typeof(GenericClass1<>))]
class ClassA { }
通过使用适当数量的逗号指定多个类型参数。 在此示例中,GenericClass2 具有两个类型参数:
public class GenericClass2<T, U> { }
[CustomAttribute(info = typeof(GenericClass2<,>))]
class ClassB { }
属性可引用封闭式构造泛型类型:
public class GenericClass3<T, U, V> { }
[CustomAttribute(info = typeof(GenericClass3<int, double, string>))]
class ClassC { }
引用泛型类型参数的特性导致一个编译时错误:
[CustomAttribute(info = typeof(GenericClass3<int, T, string>))] //Error CS0416
class ClassD<T> { }
从 C# 11 开始,泛型类型可以从 Attribute 继承:
public class CustomGenericAttribute<T> : Attribute { } //Requires C# 11
若要在运行时获取有关泛型类型或类型参数的信息,可使用 System.Reflection 方法。
使用反射查询程序集的元数据 (LINQ)
使用 .NET 反射 API 检查 .NET 程序集中的元数据,并创建位于该程序集中的类型、类型成员和参数的集合。 因为这些集合支持泛型 IEnumerable<T> 接口,所以可以使用 LINQ 查询它们。
下面的示例演示了如何将 LINQ 与反射配合使用以检索有关与指定搜索条件匹配的方法的特定元数据。 在这种情况下,该查询在返回数组等可枚举类型的程序集中查找所有方法的名称。
Assembly assembly = Assembly.Load("System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e");
var pubTypesQuery = from type in assembly.GetTypes()
where type.IsPublic
from method in type.GetMethods()
where method.ReturnType.IsArray == true
|| (method.ReturnType.GetInterface(
typeof(System.Collections.Generic.IEnumerable<>).FullName!) != null
&& method.ReturnType.FullName != "System.String")
group method.ToString() by type.ToString();
foreach (var groupOfMethods in pubTypesQuery)
{
Console.WriteLine("Type: {0}", groupOfMethods.Key);
foreach (var method in groupOfMethods)
{
Console.WriteLine(" {0}", method);
}
}