.NET进阶——深入理解反射(2)细说Type类型与实例创建

一、核心定义:System.Type 是什么?

System.Type 是 .NET 框架中 表示 "类型元数据" 的抽象基类 。简单来说:Type就相当与是一个具体类的图纸

比如当我写了这样的代码时: Type type = typeof(Person) 就表示当前这个Type类型的type是对我Person类的一个抽象图纸。我们可以通过这个type来做很多事情,比如获取它的属性和方法等,尤其和泛型、属性等配合起来,会发挥出很强大的力量,后面会介绍更多。

二、如何获取 Type 对象?

在 C# 中,有 3 种常用方式获取一个类型的 Type 实例:

1.直接通过类型名获取,无需实例,编译时检查有效性。

cs 复制代码
Type intType = typeof(int);  // 获取 int 类型的 Type 对象
Type stringType = typeof(string);  // 获取 string 类型的 Type 对象
Type personType = typeof(Person);  // 获取自定义类 Person 的 Type 对象

2. GetType() 方法(运行时通过实例获取)

通过对象实例获取其实际类型(支持多态,返回运行时类型)。

cs 复制代码
string str = "Hello";
Type type = str.GetType();  // 返回 System.String

Person person = new Person();  
Type studentType = person.GetType();  // 返回 Person 

3. Assembly.GetType()(动态加载程序集后获取)

从外部 DLL(程序集)中动态加载类型(常用于插件系统)。

cs 复制代码
// 加载外部 DLL
Assembly assembly1 = Assembly.Load("MyPlugin");           // 不需要后缀
Assembly assembly2 = Assembly.LoadFrom("MyPlugin.dll");   // 需要后缀
Assembly assembly3 = Assembly.LoadFile("D:\ASP.NET_quanzhan\csharp-advanced\Advanced_Refulaction_Methods\Advanced_Refulaction_Methods\bin\Debug\net8.0\MyPlugin.dll");   //需要完整路径

// 通过assembly.GetType方法可以获取类型,参数必须要是命名空间.类名的完整名称
Type pluginType = assembly.GetType("MyPlugin.PluginClass");

4.Type.GetType()获取(自动搜索当前程序集,自动添加)

cs 复制代码
// 语法:Type.GetType("完全限定名")
Type stringType = Type.GetType("System.String");  // 返回 System.String
Type intType = Type.GetType("System.Int32");      // 返回 System.Int32

// 语法:Type.GetType("完全限定名 , 程序集名称")
Type personType = Type.GetType("MyApp.Models.Person, MyApp");  // 格式:命名空间.类名, 程序集名

5.使用实例名.GetType时有个坑是需要注意的,来看下面的代码

cs 复制代码
object obj = "123456";
Type type1 = obj.GetType();   // 返回string

Person p = new Student();  // Student类继承自Person类
Type type2 = p.GetType();  // 返回Student而非Person

第一次看到这个结果大家可能有点吃惊,为什么会这样,原因是Type获取的是运行时类型,而非编译时类型

类型 定义 确定时机 例子(object obj = "Hello"
编译时类型 变量声明时的类型(写代码时指定) 编译时 obj 的编译时类型是 object
运行时类型 对象实际创建 时的类型(new 出来的类型) 运行时 obj 的运行时类型是 string

所以,我们这里type返回的都是实际创建的实例,而非声明类型。

cs 复制代码
object obj = "Hello";  // 声明类型是 object,实际创建的是 string 实例
Type type = obj.GetType();  // 返回 System.String

剩下两个方法typeof(Person)和assembly.GetType("命名空间.类名")这两个方法中,由于前一个是直接在编译时就获取了类型,所以前一个是编译时对象;而后一个由于要加载编译后的DLL文件,所以他是运行时对象。

cs 复制代码
    Object obj2 = "Hello";
    Type type5 = typeof(Object);  // 获取对象是Object类型

三、获取Type后创建实例

1.调用无参构造函数创建实例(最基础)

当我们的对象只有一个无参构造函数时:

cs 复制代码
    Type type = typeof(Person);
    Object instance = Activator.CreateInstance(type);

    //由于用Activator。CreateInstance创建出来的对象时Object类型,所以需要转换
    Person person = (Person)instance; 
    person.Name = "张三";     // 可以使用属性了
    person.Age = 18;

2.调用带参构造函数创建实例(有参数的情况下)

当前的Person类有一个带参构造函数如下:

cs 复制代码
    public class Person
    {
        public int Id { get; set; }
        public string? Name { get; set; }
        public string? Description { get; set; }
        public int Age { get; set; }

        public Person(string Name)
        {
            this.Name = Name;
        }
    }

这种情况下,在创建实例时必须要给定参数:

cs 复制代码
    Type type = typeof(Person);
    Object instance = Activator.CreateInstance(type,new object[] { "张三" }); // 使用object数组给定参数

    Person person = (Person)instance;
    person.Age = 18;

3. 调用非公共构造函数(如私有构造函数)

语法Activator.CreateInstance(Type type, bool nonPublic)

适用场景 :类的构造函数是 privateprotected(如单例模式的私有构造函数)。

cs 复制代码
// 假设 Singleton 类有私有构造函数:private Singleton() { }
Type singletonType = typeof(Singleton);

// 创建实例(允许调用非公共构造函数)
Singleton instance = (Singleton)Activator.CreateInstance(singletonType, true);

4.泛型类型的实例创建(特殊情况)

步骤:

  1. 获取泛型定义的 Type(如 typeof(List<>));
  2. 通过 MakeGenericType() 方法传入具体类型参数,生成具体泛型类型;
  3. 调用 Activator.CreateInstance() 创建实例。

示例:创建 List<string> 实例

cs 复制代码
// 1. 获取泛型定义:List<>(注意:<> 表示未指定类型参数的泛型定义)
Type type = typeof(List<>);

// 2. 生成具体泛型类型:List<string>(传入 string 作为类型参数)
Type GenericType = type.MakeGenericType(typeof(string));

// 3. 创建实例(相当于 new List<string>())
object list = Activator.CreateInstance(GenericType);
List<string> ListInstance = (List<string>)list;

// 4. 使用实例
ListInstance.Add("123");
ListInstance.Add("你好");
相关推荐
一个帅气昵称啊6 小时前
.Net如何优雅的实现发送邮件服务
.net·mail·邮件
时光追逐者13 小时前
一个 WPF 开源、免费的 SVG 图像查看控件
开源·c#·.net·wpf
武藤一雄14 小时前
C# 中线程安全都有哪些
后端·安全·微软·c#·.net·.netcore·线程
de之梦-御风15 小时前
【WebAPI 模拟器】.NET 8/9 + Minimal API + Swagger + DI + WPF Host
.net·wpf·web
AI题库17 小时前
NopCommerce 4.9.3开发实战 1.2 开发环境搭建指南(.NET 9+ & Visual Studio 2022)
ide·microsoft·.net·visual studio
我是唐青枫1 天前
C#.NET 索引器完全解析:语法、场景与最佳实践
c#·.net
追逐时光者1 天前
一款基于 .NET 9 构建的企业级 Web RBAC 快速开发框架
.net
幌才_loong1 天前
深入解析 C# async/await 执行原理:从语法糖到状态机
后端·.net
Caco.D1 天前
Aneiang.Pa 代理池(Proxy Pool)功能与 ASP.NET Core Web API 集成实战
爬虫·asp.net·.net·aneiang.pa
步步为营DotNet2 天前
深度解析.NET中HttpClient的连接管理机制:优化网络请求性能
网络·.net