C# 反射与泛型深度结合详解

反射(Reflection)是 C# 的 "元编程" 能力,允许程序在运行时 获取类型信息、调用方法、创建实例;泛型(Generic)则是 "类型参数化",实现类型安全的代码复用。两者结合可突破静态泛型的限制,实现动态绑定泛型参数、调用泛型方法、操作泛型成员,是框架开发(如 DI 容器、ORM、序列化)的核心技术。

本文将从 "基础概念→核心 API→分场景超详细案例→底层原理→避坑指南" 全维度讲解,所有案例均为可直接运行的控制台程序,每一行代码都附带注释和原理说明。

一、核心概念前置

在开始案例前,先明确反射操作泛型的核心术语,避免概念混淆:

|----------------------|-------------------------------------------|------------------------------------------------|
| 术语 | | 定义 | |----| | | 示例 | |----| |
| 泛型定义(未绑定类型) | 未指定具体泛型参数的泛型类型 / 方法,仅表示 "模板",无法直接实例化 / 调用 | typeof(GenericClass<>)MethodInfo(泛型方法定义) |
| 已绑定类型 / 方法 | 绑定了具体泛型参数的泛型类型 / 方法,可实例化 / 调用 | typeof(GenericClass<int>)、绑定了<string>的泛型方法 |
| 泛型参数(Type Argument) | 绑定到泛型定义的具体类型(如 int、string) | MakeGenericType(typeof(int)) 中的 int |
| 泛型形参(Type Parameter) | 泛型定义中的占位符(如<T><U>) | class GenericClass<T> 中的 T |

二、核心 API 全解析(反射操作泛型的 "工具箱")

以下是反射操作泛型的核心 API,按 "类型操作→方法操作→成员操作" 分类,每个 API 附带用途和使用场景:

2.1 泛型类型操作 API

|---------------------------------------|-----------------------------------------------------|
| API | | 用途 | |----| |
| Type.IsGenericType | 判断类型是否是已绑定的泛型类型 (如GenericClass<int>返回 true) |
| Type.IsGenericTypeDefinition | 判断类型是否是泛型定义 (如GenericClass<>返回 true) |
| Type.GetGenericTypeDefinition() | 从已绑定类型获取泛型定义(如GenericClass<int>GenericClass<>) |
| Type.MakeGenericType(params Type[]) | 绑定泛型参数,从泛型定义生成已绑定类型(核心 API) |
| Type.GetGenericArguments() | 获取泛型参数数组(已绑定类型返回具体类型,泛型定义返回形参) |

2.2 泛型方法操作 API

|-----------------------------------------------|--------------------------------|
| API | 用途 |
| MethodInfo.IsGenericMethod | 判断方法是否是泛型方法(已绑定 / 未绑定均返回 true) |
| MethodInfo.IsGenericMethodDefinition | 判断方法是否是泛型方法定义(未绑定参数) |
| MethodInfo.MakeGenericMethod(params Type[]) | 绑定泛型参数,从泛型方法定义生成已绑定方法(核心 API) |
| MethodInfo.GetGenericArguments() | 获取方法的泛型参数数组 |

2.3 实例 / 成员操作 API

|----------------------------------------------------|----------------------------|
| API | | 用途 | |----| |
| Activator.CreateInstance(Type, params object[]) | 创建泛型类型实例(支持无参 / 带参构造) |
| MethodInfo.Invoke(object, object[]) | 调用泛型方法(实例方法传实例,静态方法传 null) |
| PropertyInfo.GetValue(object)/SetValue(object) | 读写泛型类型的属性 |

三、控制台案例(分 8 个核心场景)

所有案例基于同一控制台项目,先定义测试用的泛型类型(类、接口、方法),再分场景演示反射操作。

3.0 准备测试用泛型类型(基础依赖)

先定义一套覆盖 "泛型类、泛型接口、泛型方法(实例 / 静态 / 重载)、泛型属性 / 字段" 的测试类型,后续所有反射操作均基于此:

cs 复制代码
using System;
using System.Collections.Generic;
using System.Reflection;

namespace ReflectionGenericUltraDetail
{
    #region 测试用泛型类型定义(核心依赖)
    /// <summary>
    /// 泛型测试类(包含泛型字段、属性、构造函数、实例泛型方法、静态泛型方法、重载泛型方法)
    /// </summary>
    /// <typeparam name="T">主泛型参数</typeparam>
    public class GenericTestClass<T>
    {
        // 泛型字段
        public T GenericField;

        // 泛型属性
        public T GenericProperty { get; set; }

        // 非泛型属性(对比)
        public int NonGenericProperty { get; set; } = 0;

        #region 构造函数(无参/单参/多参)
        /// <summary>
        /// 无参构造函数
        /// </summary>
        public GenericTestClass()
        {
            Console.WriteLine($"【构造函数】GenericTestClass<{typeof(T).Name}> 无参构造执行");
        }

        /// <summary>
        /// 单参构造函数(泛型参数类型)
        /// </summary>
        /// <param name="initValue">泛型类型的初始值</param>
        public GenericTestClass(T initValue)
        {
            GenericField = initValue;
            GenericProperty = initValue;
            Console.WriteLine($"【构造函数】GenericTestClass<{typeof(T).Name}> 单参构造执行,初始值:{initValue}");
        }

        /// <summary>
        /// 多参构造函数(泛型+非泛型参数)
        /// </summary>
        /// <param name="initValue">泛型初始值</param>
        /// <param name="nonGenericValue">非泛型int值</param>
        public GenericTestClass(T initValue, int nonGenericValue)
        {
            GenericField = initValue;
            GenericProperty = initValue;
            NonGenericProperty = nonGenericValue;
            Console.WriteLine($"【构造函数】GenericTestClass<{typeof(T).Name}> 多参构造执行,泛型值:{initValue},非泛型值:{nonGenericValue}");
        }
        #endregion

        #region 实例方法(泛型/非泛型/重载)
        /// <summary>
        /// 非泛型实例方法
        /// </summary>
        public void NonGenericInstanceMethod()
        {
            Console.WriteLine($"【实例方法】非泛型方法执行,泛型类型:{typeof(T).Name},GenericProperty值:{GenericProperty}");
        }

        /// <summary>
        /// 泛型实例方法(单泛型参数)
        /// </summary>
        /// <typeparam name="U">方法级泛型参数</typeparam>
        /// <param name="input1">类泛型参数T类型</param>
        /// <param name="input2">方法泛型参数U类型</param>
        public void GenericInstanceMethod<U>(T input1, U input2)
        {
            Console.WriteLine($"【实例方法】泛型方法<{typeof(U).Name}>执行,输入1({typeof(T).Name}):{input1},输入2({typeof(U).Name}):{input2}");
        }

        /// <summary>
        /// 泛型实例方法(重载版)
        /// </summary>
        /// <typeparam name="U">方法级泛型参数</typeparam>
        /// <typeparam name="V">第二个方法级泛型参数</typeparam>
        /// <param name="input1">T类型</param>
        /// <param name="input2">U类型</param>
        /// <param name="input3">V类型</param>
        public void GenericInstanceMethod<U, V>(T input1, U input2, V input3)
        {
            Console.WriteLine($"【实例方法】泛型方法<{typeof(U).Name},{typeof(V).Name}>重载版执行,输入1:{input1},输入2:{input2},输入3:{input3}");
        }
        #endregion

        #region 静态方法(泛型/非泛型)
        /// <summary>
        /// 非泛型静态方法
        /// </summary>
        /// <param name="message">字符串参数</param>
        public static void NonGenericStaticMethod(string message)
        {
            Console.WriteLine($"【静态方法】非泛型静态方法执行,消息:{message}");
        }

        /// <summary>
        /// 泛型静态方法
        /// </summary>
        /// <typeparam name="W">静态方法泛型参数</typeparam>
        /// <param name="value">W类型参数</param>
        public static void GenericStaticMethod<W>(W value)
        {
            Console.WriteLine($"【静态方法】泛型静态方法<{typeof(W).Name}>执行,值:{value}");
        }
        #endregion
    }

    /// <summary>
    /// 泛型接口(测试泛型接口反射)
    /// </summary>
    /// <typeparam name="T">接口泛型参数</typeparam>
    public interface IGenericTestInterface<T>
    {
        T GetData();
        void SetData(T data);
        void GenericInterfaceMethod<U>(T input, U output);
    }

    /// <summary>
    /// 泛型接口实现类
    /// </summary>
    /// <typeparam name="T">实现类泛型参数</typeparam>
    public class GenericInterfaceImplement<T> : IGenericTestInterface<T>
    {
        private T _data;

        public T GetData()
        {
            Console.WriteLine($"【接口实现】GetData()执行,返回值:{_data}");
            return _data;
        }

        public void SetData(T data)
        {
            _data = data;
            Console.WriteLine($"【接口实现】SetData()执行,设置值:{data}");
        }

        public void GenericInterfaceMethod<U>(T input, U output)
        {
            Console.WriteLine($"【接口实现】泛型接口方法<{typeof(U).Name}>执行,输入:{input},输出:{output}");
        }
    }
    #endregion

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("==================================== 场景1:泛型类型的反射基础操作 ====================================");
            Scene1_GenericTypeBasicOperations();

            Console.WriteLine("\n==================================== 场景2:动态创建泛型类实例(全构造函数) ====================================");
            Scene2_CreateGenericInstance();

            Console.WriteLine("\n==================================== 场景3:动态调用泛型实例方法(含重载) ====================================");
            Scene3_CallGenericInstanceMethod();

            Console.WriteLine("\n==================================== 场景4:动态调用泛型静态方法 ====================================");
            Scene4_CallGenericStaticMethod();

            Console.WriteLine("\n==================================== 场景5:反射操作泛型字段/属性 ====================================");
            Scene5_ReflectGenericFieldProperty();

            Console.WriteLine("\n==================================== 场景6:泛型接口的反射操作 ====================================");
            Scene6_ReflectGenericInterface();

            Console.WriteLine("\n==================================== 场景7:嵌套泛型的反射处理 ====================================");
            Scene7_HandleNestedGeneric();

            Console.WriteLine("\n==================================== 场景8:泛型方法重载的精准获取 ====================================");
            Scene8_GetOverloadGenericMethod();

            Console.ReadKey();
        }

3.1 场景 1:泛型类型的反射基础操作

目标:掌握 "泛型定义" 与 "已绑定类型" 的区分、核心属性判断、泛型参数获取。

cs 复制代码
        /// <summary>
        /// 场景1:泛型类型的反射基础操作(泛型定义/已绑定类型区分、参数获取)
        /// </summary>
        static void Scene1_GenericTypeBasicOperations()
        {
            // 1. 获取泛型定义(未绑定类型):typeof(类名<>),注意<>内无参数
            Type genericDefinition = typeof(GenericTestClass<>);
            Console.WriteLine($"1. 泛型定义类型名:{genericDefinition.FullName}");
            Console.WriteLine($"   - 是否是泛型定义:{genericDefinition.IsGenericTypeDefinition}");
            Console.WriteLine($"   - 是否是泛型类型:{genericDefinition.IsGenericType}"); // 泛型定义也是泛型类型
            Console.WriteLine($"   - 泛型形参数量:{genericDefinition.GetGenericArguments().Length}"); // 1个形参(T)
            Console.WriteLine($"   - 泛型形参名称:{genericDefinition.GetGenericArguments()[0].Name}"); // T

            // 2. 绑定泛型参数,生成已绑定类型(核心:MakeGenericType)
            Type boundType_Int = genericDefinition.MakeGenericType(typeof(int));
            Console.WriteLine($"\n2. 绑定int后的已绑定类型名:{boundType_Int.FullName}");
            Console.WriteLine($"   - 是否是泛型定义:{boundType_Int.IsGenericTypeDefinition}"); // false(已绑定)
            Console.WriteLine($"   - 是否是泛型类型:{boundType_Int.IsGenericType}"); // true
            Console.WriteLine($"   - 泛型实参类型:{boundType_Int.GetGenericArguments()[0].Name}"); // Int32(具体类型)

            // 3. 从已绑定类型反推泛型定义(GetGenericTypeDefinition)
            Type derivedDefinition = boundType_Int.GetGenericTypeDefinition();
            Console.WriteLine($"\n3. 从已绑定类型反推的泛型定义:{derivedDefinition.FullName}");
            Console.WriteLine($"   - 与原泛型定义是否相同:{derivedDefinition == genericDefinition}"); // true

            // 4. 非泛型类型的对比(验证属性)
            Type nonGenericType = typeof(string);
            Console.WriteLine($"\n4. 非泛型类型(string):");
            Console.WriteLine($"   - 是否是泛型类型:{nonGenericType.IsGenericType}"); // false
            Console.WriteLine($"   - 是否是泛型定义:{nonGenericType.IsGenericTypeDefinition}"); // false
        }

运行结果

cs 复制代码
1. 泛型定义类型名:ReflectionGenericUltraDetail.GenericTestClass`1
   - 是否是泛型定义:True
   - 是否是泛型类型:True
   - 泛型形参数量:1
   - 泛型形参名称:T

2. 绑定int后的已绑定类型名:ReflectionGenericUltraDetail.GenericTestClass`1[[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
   - 是否是泛型定义:False
   - 是否是泛型类型:True
   - 泛型实参类型:Int32

3. 从已绑定类型反推的泛型定义:ReflectionGenericUltraDetail.GenericTestClass`1
   - 与原泛型定义是否相同:True

4. 非泛型类型(string):
   - 是否是泛型类型:False
   - 是否是泛型定义:False

核心说明

  • 泛型定义是 "模板",无法直接实例化(Activator.CreateInstance(typeof(GenericTestClass<>)) 会报错);
  • 必须通过 MakeGenericType 绑定具体类型,生成 "已绑定类型" 后才能实例化 / 调用方法;
  • GetGenericTypeDefinition() 是 "反向操作",可从已绑定类型还原泛型定义,用于缓存泛型模板。

3.2 场景 2:动态创建泛型类实例(全构造函数)

目标:掌握无参、单参、多参构造函数的泛型实例创建,解决 "构造函数参数匹配" 问题。

cs 复制代码
        /// <summary>
        /// 场景2:动态创建泛型类实例(无参/单参/多参构造函数)
        /// </summary>
        static void Scene2_CreateGenericInstance()
        {
            // 步骤1:获取泛型定义并绑定int类型(已绑定类型)
            Type genericDefinition = typeof(GenericTestClass<>);
            Type boundType_Int = genericDefinition.MakeGenericType(typeof(int));

            // 子场景1:无参构造创建实例
            Console.WriteLine("【子场景1】无参构造创建实例");
            object instance_NoParam = Activator.CreateInstance(boundType_Int);
            Console.WriteLine($"   - 实例类型:{instance_NoParam.GetType().FullName}");
            Console.WriteLine($"   - 转换为强类型:{instance_NoParam is GenericTestClass<int>}"); // true

            // 子场景2:单参构造创建实例(参数为泛型类型)
            Console.WriteLine("\n【子场景2】单参构造创建实例(int类型参数:99)");
            object instance_SingleParam = Activator.CreateInstance(boundType_Int, 99); // 第二个参数是构造函数参数数组
            // 验证:获取GenericProperty属性值(后续场景会详解属性反射,此处先强转)
            GenericTestClass<int> strongType_SingleParam = instance_SingleParam as GenericTestClass<int>;
            Console.WriteLine($"   - 实例的GenericProperty值:{strongType_SingleParam.GenericProperty}"); // 99

            // 子场景3:多参构造创建实例(泛型参数+非泛型参数)
            Console.WriteLine("\n【子场景3】多参构造创建实例(int:88,非泛型int:1000)");
            object instance_MultiParam = Activator.CreateInstance(boundType_Int, 88, 1000);
            GenericTestClass<int> strongType_MultiParam = instance_MultiParam as GenericTestClass<int>;
            Console.WriteLine($"   - GenericProperty值:{strongType_MultiParam.GenericProperty}"); // 88
            Console.WriteLine($"   - NonGenericProperty值:{strongType_MultiParam.NonGenericProperty}"); // 1000

            // 扩展:绑定string类型,创建单参实例
            Console.WriteLine("\n【扩展】绑定string类型,单参构造(参数:\"Hello Reflection\")");
            Type boundType_String = genericDefinition.MakeGenericType(typeof(string));
            object instance_String = Activator.CreateInstance(boundType_String, "Hello Reflection");
            GenericTestClass<string> strongType_String = instance_String as GenericTestClass<string>;
            Console.WriteLine($"   - String类型实例的GenericProperty:{strongType_String.GenericProperty}");

            // 异常场景演示(构造函数参数类型不匹配)
            try
            {
                Console.WriteLine("\n【异常演示】构造函数参数类型不匹配(int类型实例传string参数)");
                Activator.CreateInstance(boundType_Int, "错误的字符串参数");
            }
            catch (TargetInvocationException ex)
            {
                Console.WriteLine($"   - 异常信息:{ex.InnerException.Message}"); // 无法将string转换为int
            }
        }

运行结果

cs 复制代码
【子场景1】无参构造创建实例
【构造函数】GenericTestClass<Int32> 无参构造执行
   - 实例类型:ReflectionGenericUltraDetail.GenericTestClass`1[[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
   - 转换为强类型:True

【子场景2】单参构造创建实例(int类型参数:99)
【构造函数】GenericTestClass<Int32> 单参构造执行,初始值:99
   - 实例的GenericProperty值:99

【子场景3】多参构造创建实例(int:88,非泛型int:1000)
【构造函数】GenericTestClass<Int32> 多参构造执行,泛型值:88,非泛型值:1000
   - GenericProperty值:88
   - NonGenericProperty值:1000

【扩展】绑定string类型,单参构造(参数:"Hello Reflection")
【构造函数】GenericTestClass<String> 单参构造执行,初始值:Hello Reflection
   - String类型实例的GenericProperty:Hello Reflection

【异常演示】构造函数参数类型不匹配(int类型实例传string参数)
   - 异常信息:Object of type 'System.String' cannot be converted to type 'System.Int32'.

核心说明

  • Activator.CreateInstance(Type, params object[]) 是创建实例的核心方法,第二个参数是构造函数的参数数组;
  • 构造函数参数类型必须与已绑定类型的泛型参数匹配,否则会抛出 TargetInvocationException(内层是类型转换异常);
  • 强转(as GenericTestClass<int>)是反射后使用实例的常用方式,前提是知道泛型参数类型。

3.3 场景 3:动态调用泛型实例方法(含重载)

目标:掌握 "泛型方法定义" 的获取、方法级泛型参数的绑定、实例方法的调用。

cs 复制代码
        /// <summary>
        /// 场景3:动态调用泛型实例方法(含方法级泛型参数绑定)
        /// </summary>
        static void Scene3_CallGenericInstanceMethod()
        {
            // 步骤1:创建泛型类实例(绑定int类型,单参构造:100)
            Type boundType_Int = typeof(GenericTestClass<int>);
            object instance = Activator.CreateInstance(boundType_Int, 100);

            // 子场景1:调用非泛型实例方法(基础)
            Console.WriteLine("【子场景1】调用非泛型实例方法");
            MethodInfo nonGenericMethod = boundType_Int.GetMethod("NonGenericInstanceMethod");
            nonGenericMethod.Invoke(instance, null); // 第二个参数:方法参数数组(无参则传null)

            // 子场景2:调用泛型实例方法(单泛型参数U)
            Console.WriteLine("\n【子场景2】调用泛型实例方法GenericInstanceMethod<U>(绑定U为string)");
            // 步骤1:获取泛型方法定义(未绑定方法)
            MethodInfo genericMethodDef = boundType_Int.GetMethod("GenericInstanceMethod");
            Console.WriteLine($"   - 方法是否是泛型定义:{genericMethodDef.IsGenericMethodDefinition}"); // true
            Console.WriteLine($"   - 方法泛型形参数量:{genericMethodDef.GetGenericArguments().Length}"); // 1(U)

            // 步骤2:绑定方法级泛型参数(U→string)
            MethodInfo boundMethod = genericMethodDef.MakeGenericMethod(typeof(string));
            Console.WriteLine($"   - 绑定后的方法名:{boundMethod.Name}");

            // 步骤3:调用方法(参数数组:input1=100(T=int),input2="测试字符串"(U=string))
            boundMethod.Invoke(instance, new object[] { 100, "测试字符串" });

            // 子场景3:调用重载的泛型实例方法(U+V两个泛型参数)
            Console.WriteLine("\n【子场景3】调用重载泛型实例方法GenericInstanceMethod<U,V>(U=double,V=DateTime)");
            // 注意:GetMethod默认获取第一个匹配名称的方法,重载需指定参数类型(场景8详解)
            MethodInfo genericMethodDef_Overload = boundType_Int.GetMethod(
                "GenericInstanceMethod",
                new Type[] { typeof(int), typeof(object), typeof(object) } // 参数类型:T=int, U=object, V=object(临时占位)
            );
            // 绑定方法泛型参数:U=double,V=DateTime
            MethodInfo boundMethod_Overload = genericMethodDef_Overload.MakeGenericMethod(typeof(double), typeof(DateTime));
            // 调用方法:input1=200(int),input2=3.14(double),input3=当前时间(DateTime)
            boundMethod_Overload.Invoke(instance, new object[] { 200, 3.14, DateTime.Now });
        }

运行结果

cs 复制代码
【构造函数】GenericTestClass<Int32> 单参构造执行,初始值:100
【子场景1】调用非泛型实例方法
【实例方法】非泛型方法执行,泛型类型:Int32,GenericProperty值:100

【子场景2】调用泛型实例方法GenericInstanceMethod<U>(绑定U为string)
   - 方法是否是泛型定义:True
   - 方法泛型形参数量:1
   - 绑定后的方法名:GenericInstanceMethod
【实例方法】泛型方法<String>执行,输入1(Int32):100,输入2(String):测试字符串

【子场景3】调用重载泛型实例方法GenericInstanceMethod<U,V>(U=double,V=DateTime)
【实例方法】泛型方法<Double,DateTime>重载版执行,输入1:200,输入2:3.14,输入3:2025/12/16 15:30:00

核心说明

  • 泛型方法的操作分三步:获取方法定义→绑定方法级泛型参数→调用(Invoke);
  • MethodInfo.Invoke(object instance, object[] parameters)
    • 第一个参数:实例方法传实例,静态方法传null
    • 第二个参数:方法参数数组,顺序必须与方法定义一致;
  • 重载方法的精准获取需指定参数类型(场景 8 详解)。

3.4 场景 4:动态调用泛型静态方法

目标:掌握静态泛型方法的获取、绑定、调用(无需实例)。

cs 复制代码
        /// <summary>
        /// 场景4:动态调用泛型静态方法(无需创建实例)
        /// </summary>
        static void Scene4_CallGenericStaticMethod()
        {
            // 步骤1:获取已绑定类型(int)
            Type boundType_Int = typeof(GenericTestClass<int>);

            // 子场景1:调用非泛型静态方法
            Console.WriteLine("【子场景1】调用非泛型静态方法");
            MethodInfo nonGenericStaticMethod = boundType_Int.GetMethod("NonGenericStaticMethod");
            nonGenericStaticMethod.Invoke(null, new object[] { "静态方法测试消息" }); // 实例参数传null

            // 子场景2:调用泛型静态方法
            Console.WriteLine("\n【子场景2】调用泛型静态方法GenericStaticMethod<W>(绑定W为bool)");
            // 步骤1:获取泛型静态方法定义
            MethodInfo genericStaticMethodDef = boundType_Int.GetMethod("GenericStaticMethod");
            Console.WriteLine($"   - 是否是泛型方法定义:{genericStaticMethodDef.IsGenericMethodDefinition}"); // true

            // 步骤2:绑定方法泛型参数W→bool
            MethodInfo boundStaticMethod = genericStaticMethodDef.MakeGenericMethod(typeof(bool));

            // 步骤3:调用静态方法(实例参数null,方法参数:true)
            boundStaticMethod.Invoke(null, new object[] { true });

            // 扩展:绑定不同泛型参数(W=DateTime)
            Console.WriteLine("\n【扩展】绑定W=DateTime调用泛型静态方法");
            MethodInfo boundStaticMethod_DateTime = genericStaticMethodDef.MakeGenericMethod(typeof(DateTime));
            boundStaticMethod_DateTime.Invoke(null, new object[] { DateTime.Now });
        }

运行结果

cs 复制代码
【子场景1】调用非泛型静态方法
【静态方法】非泛型静态方法执行,消息:静态方法测试消息

【子场景2】调用泛型静态方法GenericStaticMethod<W>(绑定W为bool)
   - 是否是泛型方法定义:True
【静态方法】泛型静态方法<Boolean>执行,值:True

【扩展】绑定W=DateTime调用泛型静态方法
【静态方法】泛型静态方法<DateTime>执行,值:2025/12/16 15:30:00

核心说明

  • 静态方法调用时,Invoke 的第一个参数必须传null
  • 泛型静态方法的绑定逻辑与实例泛型方法一致,区别仅在于 "无需实例";
  • 静态方法属于类型本身,与实例无关,因此无需创建泛型类实例。

3.5 场景 5:反射操作泛型字段 / 属性

目标:掌握泛型类型的字段、属性的读取和修改,解决 "动态访问泛型成员" 问题。

cs 复制代码
        /// <summary>
        /// 场景5:反射操作泛型字段/属性(读取/修改)
        /// </summary>
        static void Scene5_ReflectGenericFieldProperty()
        {
            // 步骤1:创建泛型实例(绑定string类型,单参构造:"初始值")
            Type boundType_String = typeof(GenericTestClass<string>);
            object instance = Activator.CreateInstance(boundType_String, "初始值");

            // 子场景1:操作泛型字段GenericField
            Console.WriteLine("【子场景1】操作泛型字段GenericField");
            FieldInfo genericField = boundType_String.GetField("GenericField");
            // 读取字段值
            object fieldValue = genericField.GetValue(instance);
            Console.WriteLine($"   - 原始字段值:{fieldValue}");
            // 修改字段值
            genericField.SetValue(instance, "修改后的字段值");
            Console.WriteLine($"   - 修改后的字段值:{genericField.GetValue(instance)}");

            // 子场景2:操作泛型属性GenericProperty
            Console.WriteLine("\n【子场景2】操作泛型属性GenericProperty");
            PropertyInfo genericProperty = boundType_String.GetProperty("GenericProperty");
            // 读取属性值
            object propValue = genericProperty.GetValue(instance);
            Console.WriteLine($"   - 原始属性值:{propValue}");
            // 修改属性值
            genericProperty.SetValue(instance, "修改后的属性值");
            Console.WriteLine($"   - 修改后的属性值:{genericProperty.GetValue(instance)}");

            // 子场景3:操作非泛型属性NonGenericProperty
            Console.WriteLine("\n【子场景3】操作非泛型属性NonGenericProperty");
            PropertyInfo nonGenericProp = boundType_String.GetProperty("NonGenericProperty");
            Console.WriteLine($"   - 原始值:{nonGenericProp.GetValue(instance)}"); // 默认0
            nonGenericProp.SetValue(instance, 999);
            Console.WriteLine($"   - 修改后值:{nonGenericProp.GetValue(instance)}"); // 999

            // 异常场景:字段/属性不存在
            try
            {
                Console.WriteLine("\n【异常演示】获取不存在的字段");
                boundType_String.GetField("不存在的字段");
            }
            catch (NullReferenceException ex)
            {
                Console.WriteLine($"   - 异常:{ex.Message}");
            }
        }

运行结果

cs 复制代码
【构造函数】GenericTestClass<String> 单参构造执行,初始值:初始值
【子场景1】操作泛型字段GenericField
   - 原始字段值:初始值
   - 修改后的字段值:修改后的字段值

【子场景2】操作泛型属性GenericProperty
   - 原始属性值:初始值
   - 修改后的属性值:修改后的属性值

【子场景3】操作非泛型属性NonGenericProperty
   - 原始值:0
   - 修改后值:999

【异常演示】获取不存在的字段
   - 异常:Object reference not set to an instance of an object.

核心说明

  • FieldInfo.GetValue(object)/SetValue(object, object):读取 / 修改字段值,参数为实例和新值;
  • PropertyInfo.GetValue(object)/SetValue(object, object):读取 / 修改属性值,逻辑与字段一致;
  • 泛型字段 / 属性的类型由已绑定类型的泛型参数决定(如绑定 string 则字段类型为 string);
  • 获取成员时名称必须完全匹配(区分大小写),否则返回null,调用GetValue会抛空引用异常。

3.6 场景 6:泛型接口的反射操作

目标:掌握泛型接口的获取、接口方法的调用、实现类的反射。

cs 复制代码
        /// <summary>
        /// 场景6:泛型接口的反射操作(获取接口、调用接口方法)
        /// </summary>
        static void Scene6_ReflectGenericInterface()
        {
            // 步骤1:获取泛型接口实现类的已绑定类型(绑定double)
            Type implementType_Double = typeof(GenericInterfaceImplement<double>);

            // 子场景1:检查实现类是否实现泛型接口
            Console.WriteLine("【子场景1】检查实现类是否实现泛型接口");
            // 获取接口类型:GetInterface("接口名`泛型参数个数"),`1表示1个泛型参数
            Type genericInterfaceType = implementType_Double.GetInterface("IGenericTestInterface`1");
            Console.WriteLine($"   - 是否实现IGenericTestInterface<T>:{genericInterfaceType != null}"); // true
            Console.WriteLine($"   - 接口泛型实参:{genericInterfaceType.GetGenericArguments()[0].Name}"); // Double

            // 子场景2:创建实现类实例并调用接口方法
            Console.WriteLine("\n【子场景2】调用泛型接口方法");
            object instance = Activator.CreateInstance(implementType_Double);

            // 调用SetData方法
            MethodInfo setDataMethod = genericInterfaceType.GetMethod("SetData");
            setDataMethod.Invoke(instance, new object[] { 3.1415926 }); // 参数:double类型的π

            // 调用GetData方法
            MethodInfo getDataMethod = genericInterfaceType.GetMethod("GetData");
            object data = getDataMethod.Invoke(instance, null);
            Console.WriteLine($"   - GetData返回值:{data}");

            // 调用接口的泛型方法GenericInterfaceMethod<U>
            Console.WriteLine("\n【子场景3】调用接口的泛型方法");
            MethodInfo interfaceGenericMethodDef = genericInterfaceType.GetMethod("GenericInterfaceMethod");
            // 绑定方法泛型参数U为string
            MethodInfo boundInterfaceMethod = interfaceGenericMethodDef.MakeGenericMethod(typeof(string));
            // 调用方法:input=2.718(double),output="自然常数e"(string)
            boundInterfaceMethod.Invoke(instance, new object[] { 2.718, "自然常数e" });
        }

运行结果

cs 复制代码
【子场景1】检查实现类是否实现泛型接口
   - 是否实现IGenericTestInterface<T>:True
   - 接口泛型实参:Double

【子场景2】调用泛型接口方法
【接口实现】SetData()执行,设置值:3.1415926
【接口实现】GetData()执行,返回值:3.1415926
   - GetData返回值:3.1415926

【子场景3】调用接口的泛型方法
【接口实现】泛型接口方法<String>执行,输入:2.718,输出:自然常数e

核心说明

  • 获取泛型接口需使用 GetInterface("接口名泛型参数个数 ")(如IGenericTestInterface1),1表示接口有 1 个泛型参数;
  • 泛型接口的方法调用逻辑与泛型类方法一致,区别在于 "方法定义来自接口类型";
  • 实现类的泛型参数会自动传递给接口的泛型参数(如GenericInterfaceImplement<double>IGenericTestInterface<double>)。

3.7 场景 7:嵌套泛型的反射处理

目标 :掌握嵌套泛型(如List<Dictionary<int, string>>)的反射,解决复杂泛型类型的操作问题。

cs 复制代码
        /// <summary>
        /// 场景7:处理嵌套泛型(如List<Dictionary<int, string>>)
        /// </summary>
        static void Scene7_HandleNestedGeneric()
        {
            // 需求:动态创建List<Dictionary<int, string>>并添加元素

            // 步骤1:定义嵌套泛型的层级
            // 内层:Dictionary<int, string>
            Type dictGenericDef = typeof(Dictionary<,>); // 2个泛型参数
            Type dictBoundType = dictGenericDef.MakeGenericType(typeof(int), typeof(string));
            // 外层:List<Dictionary<int, string>>
            Type listGenericDef = typeof(List<>); // 1个泛型参数
            Type listBoundType = listGenericDef.MakeGenericType(dictBoundType);

            Console.WriteLine($"嵌套泛型类型名:{listBoundType.FullName}");

            // 步骤2:创建List实例
            object listInstance = Activator.CreateInstance(listBoundType);
            Console.WriteLine($"List实例类型:{listInstance.GetType().Name}");

            // 步骤3:创建Dictionary实例并添加元素
            object dictInstance = Activator.CreateInstance(dictBoundType);
            // 调用Dictionary的Add方法(key=1,value="Apple")
            MethodInfo dictAddMethod = dictBoundType.GetMethod("Add");
            dictAddMethod.Invoke(dictInstance, new object[] { 1, "Apple" });
            dictAddMethod.Invoke(dictInstance, new object[] { 2, "Banana" });

            // 步骤4:将Dictionary添加到List中
            MethodInfo listAddMethod = listBoundType.GetMethod("Add");
            listAddMethod.Invoke(listInstance, new object[] { dictInstance });

            // 步骤5:验证List的Count属性
            PropertyInfo listCountProp = listBoundType.GetProperty("Count");
            int count = (int)listCountProp.GetValue(listInstance);
            Console.WriteLine($"List<Dictionary<int,string>>的元素个数:{count}");

            // 步骤6:读取Dictionary的元素(扩展)
            MethodInfo dictTryGetValueMethod = dictBoundType.GetMethod("TryGetValue");
            object[] tryGetValueParams = new object[] { 1, null }; // out参数初始为null
            bool success = (bool)dictTryGetValueMethod.Invoke(dictInstance, tryGetValueParams);
            if (success)
            {
                Console.WriteLine($"Dictionary中key=1的值:{tryGetValueParams[1]}"); // out参数在索引1
            }
        }

运行结果

cs 复制代码
嵌套泛型类型名:System.Collections.Generic.List`1[[System.Collections.Generic.Dictionary`2[[System.Int32, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]
List实例类型:List`1
List<Dictionary<int,string>>的元素个数:1
Dictionary中key=1的值:Apple

核心说明

  • 嵌套泛型的处理需 "从内到外" 绑定泛型参数:先绑定内层(Dictionary),再绑定外层(List);
  • out参数的处理:调用方法时需传入长度匹配的数组,out参数的值会填充到数组对应位置;
  • 嵌套泛型是框架开发的高频场景(如 ORM 的IQueryable<Dictionary<string, object>>)。

3.8 场景 8:泛型方法重载的精准获取

目标:解决 "泛型方法重载时 GetMethod 获取错误方法" 的问题,掌握 "参数类型匹配" 的精准获取方式。

cs 复制代码
        /// <summary>
        /// 场景8:精准获取重载的泛型方法(解决GetMethod默认获取第一个匹配方法的问题)
        /// </summary>
        static void Scene8_GetOverloadGenericMethod()
        {
            // 步骤1:获取已绑定类型(int)
            Type boundType_Int = typeof(GenericTestClass<int>);

            // 问题:GenericInstanceMethod有两个重载(1个参数泛型/2个参数泛型),默认GetMethod会获取第一个
            // 解决:通过参数类型数组精准匹配

            Console.WriteLine("【子场景1】获取单参数泛型方法(GenericInstanceMethod<U>(T, U))");
            // 参数类型数组:T=int,U=object(方法参数的类型,U是泛型参数,临时用object占位)
            Type[] singleParamMethodTypes = new Type[] { typeof(int), typeof(object) };
            MethodInfo singleParamGenericMethod = boundType_Int.GetMethod(
                "GenericInstanceMethod",
                singleParamMethodTypes
            );
            Console.WriteLine($"   - 方法是否是泛型定义:{singleParamGenericMethod.IsGenericMethodDefinition}");
            Console.WriteLine($"   - 方法参数个数:{singleParamGenericMethod.GetParameters().Length}"); // 2个参数(T, U)
            // 绑定U为DateTime并调用
            MethodInfo boundSingleMethod = singleParamGenericMethod.MakeGenericMethod(typeof(DateTime));
            object instance = Activator.CreateInstance(boundType_Int, 500);
            boundSingleMethod.Invoke(instance, new object[] { 500, DateTime.Now });

            Console.WriteLine("\n【子场景2】获取双参数泛型方法(GenericInstanceMethod<U,V>(T, U, V))");
            // 参数类型数组:T=int,U=object,V=object
            Type[] doubleParamMethodTypes = new Type[] { typeof(int), typeof(object), typeof(object) };
            MethodInfo doubleParamGenericMethod = boundType_Int.GetMethod(
                "GenericInstanceMethod",
                doubleParamMethodTypes
            );
            Console.WriteLine($"   - 方法参数个数:{doubleParamGenericMethod.GetParameters().Length}"); // 3个参数(T, U, V)
            // 绑定U=float,V=Guid并调用
            MethodInfo boundDoubleMethod = doubleParamGenericMethod.MakeGenericMethod(typeof(float), typeof(Guid));
            boundDoubleMethod.Invoke(instance, new object[] { 600, 1.23f, Guid.NewGuid() });
        }
    }
}

运行结果

cs 复制代码
【子场景1】获取单参数泛型方法(GenericInstanceMethod<U>(T, U))
   - 方法是否是泛型定义:True
   - 方法参数个数:2
【构造函数】GenericTestClass<Int32> 单参构造执行,初始值:500
【实例方法】泛型方法<DateTime>执行,输入1(Int32):500,输入2(DateTime):2025/12/16 15:30:00

【子场景2】获取双参数泛型方法(GenericInstanceMethod<U,V>(T, U, V))
   - 方法参数个数:3
【实例方法】泛型方法<Single,Guid>重载版执行,输入1:600,输入2:1.23,输入3:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

核心说明

  • 泛型方法重载的区分核心是 "参数个数 + 参数类型";
  • 方法级泛型参数(如 U、V)在获取方法时需用object占位,绑定泛型参数后再传入具体类型;
  • 若重载方法的参数类型不同(如int vs string),需精准指定参数类型数组,避免获取错误方法。

四、反射操作泛型的底层原理与性能优化

4.1 底层原理

  • 泛型类型在 CLR 中是 "模板生成":每个不同的泛型参数绑定(如GenericClass<int>GenericClass<string>)会生成独立的 IL 代码;
  • 反射操作泛型的本质是 "运行时解析泛型元数据":CLR 维护了泛型类型的元数据(泛型定义、参数、方法),反射 API 通过读取这些元数据实现动态操作;
  • MakeGenericType 的底层是 "绑定泛型参数到元数据模板,生成新的 Type 对象"。

4.2 性能优化

反射操作的性能远低于静态调用,高频场景需优化:

缓存核心对象 :缓存TypeMethodInfoPropertyInfo等对象,避免重复调用GetType()/GetMethod()

cs 复制代码
// 示例:缓存泛型方法定义
private static readonly MethodInfo _cachedGenericMethod = typeof(GenericTestClass<int>).GetMethod("GenericInstanceMethod");
  1. 使用 Delegate 减少 Invoke 开销 :将MethodInfo转换为强类型委托,避免每次Invoke的反射开销;
  2. 避免频繁创建实例 :复用泛型实例,减少Activator.CreateInstance的调用;
  3. 使用表达式树(Expression)替代反射:对于高频调用的泛型方法,可通过表达式树动态生成委托,性能接近静态调用。

五、避坑指南(常见错误与解决方案)

|--------------------------------------------|-------------------------------------------------------------|---------------------------------------------------|
| 常见错误 | | 原因 | |----| | 解决方案 |
| MakeGenericType 传入参数个数不匹配 | 泛型定义的形参个数与传入的实参个数不一致(如<T>传 2 个类型) | 检查typeof(类名<>)的泛型参数个数,确保MakeGenericType参数个数匹配 |
| Invoke 抛出TargetParameterCountException | 方法参数数组长度与方法定义的参数个数不一致 | 核对方法参数个数,确保Invoke的第二个参数数组长度匹配 |
| Invoke 抛出ArgumentException | 参数类型与方法定义的参数类型不匹配(如 int 传 string) | |---------------------| | 确保参数类型与已绑定类型的泛型参数一致 | |
| GetMethod 返回null | 方法名错误 / 重载匹配失败 / 非公共方法(默认 GetMethod 只获取公共方法) | 检查方法名大小写 / 指定参数类型数组 / 使用BindingFlags获取非公共方法 |
| 泛型接口获取失败 | 接口名未加泛型参数个数(如IGenericInterface而非IGenericInterface1`) | 使用GetInterface("接口名参数个数 ")` |

相关推荐
feifeigo1235 小时前
C#中实现控件拖动功能
开发语言·c#
曹牧5 小时前
C#:List<string>类型的集合转换成用逗号分隔的字符串
开发语言·c#·list
fengfuyao9855 小时前
基于C# WinForm的收银管理系统实现
开发语言·c#
Lv11770085 小时前
Visual Studio 中的 ArrayList数组 和 List数组
数据结构·笔记·c#·list·visual studio
布伦鸽5 小时前
C# WPF -MaterialDesignTheme 找不到资源“xxx“问题记录
开发语言·c#·wpf
唐青枫5 小时前
C#.NET ref struct 深度解析:语义、限制与最佳实践
c#·.net
FuckPatience7 小时前
C# 项目调试的时候进不去断点
开发语言·c#
元亓亓亓7 小时前
考研408--组成原理--day8--汇编指令&不同语句的机器级表示
开发语言·汇编·c#
小小代码团16 小时前
2026 Office Online Server (全网最新/最详细/含问题修复) 终极部署教程
windows·microsoft·c#