.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("你好");
相关推荐
小码编匠2 小时前
C# 实现网络文件传输:打造稳定可靠的工业级工具
后端·c#·.net
关关长语8 小时前
基于NCrontab实现Covarel扩展秒级任务调度
c#·.net
MoFe19 小时前
【.net/.net core】【报错处理】另一个 SqlParameterCollection 中已包含 SqlParameter。
java·.net·.netcore
缺点内向10 小时前
如何在C#中添加Excel文档属性?
开发语言·数据库·c#·.net·excel
幌才_loong1 天前
.NET8 × Redis 实战宝典:从配置到落地,搞定高并发缓存就这篇!
后端·.net
幌才_loong1 天前
.NET8+Autofac 实战宝典:从组件拆解到场景落地的依赖注入新范式
后端·.net
百锦再1 天前
.NET到Java的终极迁移指南:最快转型路线图
android·java·开发语言·python·rust·go·.net
我是苏苏1 天前
开发工具:notepad++的下载和基本操作
运维·nginx·ai·.net·.netcore
野奔在山外的猫1 天前
【解决】.NET SDK 下载缓慢的解决方法
.net