本篇定位 这是 C# 反射系列的第四篇,我们学习如何通过反射处理泛型类型 。读完你会理解:
泛型类型和非泛型类型的区别
如何获取泛型参数
如何处理泛型方法
如何检查泛型约束
实战例子:泛型容器序列化
1. 泛型类型基础 开放泛型类型 vs 封闭泛型类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Container <T >{ public T Value { get ; set ; } } Type openType = typeof (Container<>); Console.WriteLine(openType.Name); Console.WriteLine(openType.IsGenericTypeDefinition); Type closedType = typeof (Container<string >); Console.WriteLine(closedType.Name); Console.WriteLine(closedType.IsGenericTypeDefinition); Console.WriteLine(openType.IsGenericType); Console.WriteLine(closedType.IsGenericType);
获取泛型参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class Pair <T1 , T2 >{ public T1 First { get ; set ; } public T2 Second { get ; set ; } } Type type = typeof (Pair<string , int >); Type[] genericArgs = type.GetGenericArguments(); Console.WriteLine($"泛型参数个数: {genericArgs.Length} " ); foreach (var arg in genericArgs){ Console.WriteLine($"泛型参数: {arg.Name} " ); } Type openType = typeof (Pair<,>); Type[] genericParams = openType.GetGenericArguments(); Console.WriteLine($"泛型参数定义: {genericParams[0 ].Name} " );
2. 泛型类型的反射操作 创建泛型类型实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class Box <T >{ public T Content { get ; set ; } public Box () { } public Box (T content ) { Content = content; } } Type boxType = typeof (Box<string >); object box1 = Activator.CreateInstance(boxType, "Hello" );Console.WriteLine(((Box<string >)box1).Content); Type openBoxType = typeof (Box<>); Type closedBoxType = openBoxType.MakeGenericType(typeof (int )); object box2 = Activator.CreateInstance(closedBoxType, 42 );Console.WriteLine(((Box<int >)box2).Content); Type openPairType = typeof (Pair<,>); Type closedPairType = openPairType.MakeGenericType(typeof (string ), typeof (double )); object pair = Activator.CreateInstance(closedPairType);Console.WriteLine(pair.GetType().Name);
访问泛型类型的属性 1 2 3 4 5 6 7 8 9 Type type = typeof (Box<string >); PropertyInfo contentProp = type.GetProperty("Content" ); var box = new Box<string > { Content = "Test" };object value = contentProp.GetValue(box);Console.WriteLine(value ); contentProp.SetValue(box, "Updated" ); Console.WriteLine(box.Content);
3. 泛型方法的反射 获取泛型方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class GenericMethods { public T GetDefault <T >() => default (T); public T Convert <T >(object value ) => (T)System.Convert.ChangeType(value , typeof (T)); public void Print <T >(T value ) => Console.WriteLine($"值: {value } " ); public T[] CreateArray <T >(int length ) => new T[length]; } Type type = typeof (GenericMethods); MethodInfo method = type.GetMethod("GetDefault" ); Console.WriteLine(method.IsGenericMethodDefinition); Type[] genericParams = method.GetGenericArguments(); Console.WriteLine($"泛型参数个数: {genericParams.Length} " );
调用泛型方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Type type = typeof (GenericMethods); object instance = Activator.CreateInstance(type);MethodInfo method = type.GetMethod("GetDefault" ); MethodInfo intMethod = method.MakeGenericMethod(typeof (int )); object result1 = intMethod.Invoke(instance, null );Console.WriteLine(result1); MethodInfo stringMethod = method.MakeGenericMethod(typeof (string )); object result2 = stringMethod.Invoke(instance, null );Console.WriteLine(result2); MethodInfo convertMethod = type.GetMethod("Convert" ); MethodInfo intConvertMethod = convertMethod.MakeGenericMethod(typeof (int )); object result3 = intConvertMethod.Invoke(instance, new object [] { "42" });Console.WriteLine(result3);
处理多个泛型参数的方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class MultiGeneric { public TResult Convert <TSource , TResult >(TSource source ) { return (TResult)(object )source; } } Type type = typeof (MultiGeneric); object instance = Activator.CreateInstance(type);MethodInfo method = type.GetMethod("Convert" ); MethodInfo specificMethod = method.MakeGenericMethod(typeof (int ), typeof (string )); object result = specificMethod.Invoke(instance, new object [] { 42 });Console.WriteLine(result);
4. 泛型约束的处理 获取泛型约束 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class Constrained <T > where T : class , IComparable <T >, new (){ } Type type = typeof (Constrained<>); Type[] genericParams = type.GetGenericArguments(); Type paramT = genericParams[0 ]; Type[] constraints = paramT.GetGenericParameterConstraints(); Console.WriteLine($"约束个数: {constraints.Length} " ); foreach (var constraint in constraints){ Console.WriteLine($"约束: {constraint.Name} " ); } GenericParameterAttributes attrs = paramT.GenericParameterAttributes; Console.WriteLine($"是引用类型: {(attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0 } " ); Console.WriteLine($"是值类型: {(attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0 } " ); Console.WriteLine($"有无参构造函数: {(attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0 } " );
检查类型是否满足约束 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public class TypeChecker { public static bool SatisfiesConstraints (Type typeArg, Type genericParam ) { if ((genericParam.GenericParameterAttributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0 ) { if (typeArg.IsValueType) return false ; } if ((genericParam.GenericParameterAttributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0 ) { if (!typeArg.IsValueType) return false ; } if ((genericParam.GenericParameterAttributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0 ) { if (typeArg.GetConstructor(Type.EmptyTypes) == null ) return false ; } Type[] constraints = genericParam.GetGenericParameterConstraints(); foreach (var constraint in constraints) { if (constraint.IsInterface) { if (!constraint.IsAssignableFrom(typeArg)) return false ; } else { if (!constraint.IsAssignableFrom(typeArg)) return false ; } } return true ; } } Console.WriteLine(TypeChecker.SatisfiesConstraints(typeof (string ), typeof (Constrained<>).GetGenericArguments()[0 ])); Console.WriteLine(TypeChecker.SatisfiesConstraints(typeof (int ), typeof (Constrained<>).GetGenericArguments()[0 ]));
5. 实战例子:泛型容器序列化 让我们实现一个通用的序列化器,支持泛型容器:
定义序列化接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 public interface ISerializer { string Serialize (object obj ) ; object Deserialize (string json, Type type ) ; } public class SimpleJsonSerializer : ISerializer { public string Serialize (object obj ) { if (obj == null ) return "null" ; Type type = obj.GetType(); if (type.IsPrimitive || type == typeof (string )) { return type == typeof (string ) ? $"\"{obj} \"" : obj.ToString(); } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof (List<>)) { return SerializeList(obj); } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof (Dictionary<,>)) { return SerializeDictionary(obj); } return SerializeObject(obj); } private string SerializeList (object obj ) { Type listType = obj.GetType(); Type elementType = listType.GetGenericArguments()[0 ]; var items = new List<string >(); foreach (var item in (System.Collections.IEnumerable )obj) { items.Add(Serialize(item)); } return $"[{string .Join("," , items)} ]" ; } private string SerializeDictionary (object obj ) { Type dictType = obj.GetType(); Type[] genericArgs = dictType.GetGenericArguments(); Type keyType = genericArgs[0 ]; Type valueType = genericArgs[1 ]; var items = new List<string >(); var dict = (System.Collections.IDictionary)obj; foreach (var key in dict.Keys) { var value = dict[key]; items.Add($"\"{key} \":{Serialize(value )} " ); } return $"{{{string .Join("," , items)} }}" ; } private string SerializeObject (object obj ) { Type type = obj.GetType(); var items = new List<string >(); PropertyInfo[] properties = type.GetProperties(); foreach (var prop in properties) { object value = prop.GetValue(obj); items.Add($"\"{prop.Name} \":{Serialize(value )} " ); } return $"{{{string .Join("," , items)} }}" ; } public object Deserialize (string json, Type type ) { throw new NotImplementedException(); } }
使用序列化器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Product { public string Name { get ; set ; } public decimal Price { get ; set ; } } var serializer = new SimpleJsonSerializer();var products = new List<Product>{ new Product { Name = "Laptop" , Price = 999.99 m }, new Product { Name = "Mouse" , Price = 29.99 m } }; string json1 = serializer.Serialize(products);Console.WriteLine(json1); var inventory = new Dictionary<string , int >{ { "Laptop" , 5 }, { "Mouse" , 20 } }; string json2 = serializer.Serialize(inventory);Console.WriteLine(json2);
6. 实战例子:泛型工厂 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 public class GenericFactory { private static readonly Dictionary<string , Type> _typeRegistry = new (); public static void Register <T >(string key ) where T : class { _typeRegistry[key] = typeof (T); } public static T Create <T >(string key ) where T : class { if (!_typeRegistry.ContainsKey(key)) throw new InvalidOperationException($"类型 {key} 未注册" ); Type type = _typeRegistry[key]; if (!typeof (T).IsAssignableFrom(type)) throw new InvalidOperationException($"类型 {type.Name} 不能转换为 {typeof (T).Name} " ); return (T)Activator.CreateInstance(type); } public static object Create (string key ) { if (!_typeRegistry.ContainsKey(key)) throw new InvalidOperationException($"类型 {key} 未注册" ); Type type = _typeRegistry[key]; return Activator.CreateInstance(type); } } public interface ILogger { void Log (string message ) ; } public class ConsoleLogger : ILogger { public void Log (string message ) => Console.WriteLine($"[LOG] {message} " ); } public class FileLogger : ILogger { public void Log (string message ) => Console.WriteLine($"[FILE] {message} " ); } GenericFactory.Register<ConsoleLogger>("console" ); GenericFactory.Register<FileLogger>("file" ); ILogger logger1 = GenericFactory.Create<ILogger>("console" ); logger1.Log("Hello" ); ILogger logger2 = GenericFactory.Create<ILogger>("file" ); logger2.Log("World" );
7. 泛型反射的性能考虑 缓存泛型类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class GenericTypeCache { private static readonly Dictionary<(Type, Type[]), Type> _cache = new (); public static Type GetGenericType (Type genericDefinition, params Type[] typeArguments ) { var key = (genericDefinition, typeArguments); if (!_cache.ContainsKey(key)) { _cache[key] = genericDefinition.MakeGenericType(typeArguments); } return _cache[key]; } } Type listStringType = GenericTypeCache.GetGenericType(typeof (List<>), typeof (string )); Type listIntType = GenericTypeCache.GetGenericType(typeof (List<>), typeof (int ));
避免重复的 MakeGenericType 调用 1 2 3 4 5 6 7 8 9 10 11 12 13 for (int i = 0 ; i < 1000 ; i++){ Type type = typeof (List<>).MakeGenericType(typeof (string )); var instance = Activator.CreateInstance(type); } Type listStringType = typeof (List<>).MakeGenericType(typeof (string )); for (int i = 0 ; i < 1000 ; i++){ var instance = Activator.CreateInstance(listStringType); }
8. 常见泛型反射模式 检查是否是特定泛型类型 1 2 3 4 5 6 7 8 9 10 public static bool IsGenericListOf (Type type, Type elementType ){ return type.IsGenericType && type.GetGenericTypeDefinition() == typeof (List<>) && type.GetGenericArguments()[0 ] == elementType; } Console.WriteLine(IsGenericListOf(typeof (List<string >), typeof (string ))); Console.WriteLine(IsGenericListOf(typeof (List<int >), typeof (string )));
获取泛型基类的泛型参数 1 2 3 4 5 6 7 8 9 10 11 public class Repository <T > { }public class UserRepository : Repository <User > { }Type type = typeof (UserRepository); Type baseType = type.BaseType; if (baseType.IsGenericType){ Type[] genericArgs = baseType.GetGenericArguments(); Console.WriteLine($"泛型参数: {genericArgs[0 ].Name} " ); }
总结
开放泛型类型 vs 封闭泛型类型 :使用 IsGenericTypeDefinition 区分
获取泛型参数 :使用 GetGenericArguments()
创建泛型类型 :使用 MakeGenericType()
调用泛型方法 :使用 MakeGenericMethod()
泛型约束 :使用 GetGenericParameterConstraints() 和 GenericParameterAttributes
性能 :缓存泛型类型和方法以避免重复反射
下一篇我们将学习性能优化 和表达式树 的使用。