一、核心定义: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.泛型类型的实例创建(特殊情况)
步骤:
- 获取泛型定义的
Type(如typeof(List<>)); - 通过
MakeGenericType()方法传入具体类型参数,生成具体泛型类型; - 调用
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("你好");