.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)

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

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("你好");
相关推荐
小羊没烦恼!3 小时前
【译】利用Asp.net MVC处理文件的上传下载
开发语言·缓存·c#·word·powerpoint·.net
唐青枫1 天前
我用 C# 开发了一款电子发票自动整理工具
c#·.net
我是唐青枫1 天前
我用 C# 开发了一款电子发票自动整理工具
c#·.net
唐青枫1 天前
别把 WPF 写成一个 MainWindow:C#.NET Prism 模块化开发详解
c#·.net
小羊没烦恼!7 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
_Jonas7 天前
.net framework开发环境正式环境配置文件的切换
.net·wpf
Y3815326629 天前
C# 调用谷歌搜索 API:HttpClient 与 System.Text.Json 实战
搜索引擎·.net
qq_410194299 天前
.NET 8.0 下基于 PaddleOCRSharp 的离线文字识别落地指南
算法·.net
唐青枫11 天前
别急着拆服务:C#.NET 微服务架构从边界设计到实战
c#·.net
唐青枫12 天前
别把 Razor 当成几段 HTML:C#.NET Razor Pages、MVC 视图与实战详解
c#·.net