文章目录
-
-
- [1. 第一性原理](#1. 第一性原理)
- [2. 基础用法](#2. 基础用法)
- [3. 常用使用场景](#3. 常用使用场景)
-
- [A. 反射 (Reflection) 与 属性 (Attributes) 检查](#A. 反射 (Reflection) 与 属性 (Attributes) 检查)
- [B. 依赖注入 (Dependency Injection) 注册](#B. 依赖注入 (Dependency Injection) 注册)
- [C. 泛型检查与比较](#C. 泛型检查与比较)
- [4. 注意事项](#4. 注意事项)
- [5. typeof vs GetType() 决策流程](#5. typeof vs GetType() 决策流程)
- [6. 核心区别对比](#6. 核心区别对比)
- [7. 示例](#7. 示例)
-
- [typeof 结合 反射 (Reflection) 调用私有方法](#typeof 结合 反射 (Reflection) 调用私有方法)
-
- [1. 实战代码:调用私有方法](#1. 实战代码:调用私有方法)
- [2. 关键参数:BindingFlags 详解](#2. 关键参数:BindingFlags 详解)
- [3. 性能警告](#3. 性能警告)
- [8. 易混淆](#8. 易混淆)
-
它的作用是在编译时获取类型的
System.Type对象。它就像是类型的"身份证查询器",通过它你可以知道这个类叫什么、有哪些方法、属性是什么。
在 C# 编程中,typeof 是进入 .NET 元数据(Metadata)世界的入口。它是一个编译时运算符,用于获取指定类型的 System.Type 对象。
1. 第一性原理
typeof 的本质是:在编译阶段锁定类型元数据的引用。它不需要创建对象实例,直接从程序集的元数据表中提取类型信息。
typeof 的核心本质 是:类型句柄的静态提取。它在程序编译成 IL(中间语言)时,就已经确定了指向元数据中特定类型的引用。
2. 基础用法
typeof 后面必须接类型名称(类名、结构体名、接口名等),不能接变量名,返回该类型的元数据快照。
csharp
// 1. 获取内置类型的 Type 对象
Type intType = typeof(int);
Console.WriteLine(intType.FullName); // 输出 System.Int32
Console.WriteLine(intType.Name); // 输出: Int32
Type stringType = typeof(string);
// System.String
// 2. 获取自定义类型的 Type 对象
Type userType = typeof(UserStore);
// UserQuery+UserStore
// 3. 获取泛型定义(未绑定类型参数)
Type genericType = typeof(List<>);
// System.Collections.Generic.List`1[T]
// 4. 获取具体泛型类型
Type listType = typeof(List<string>);
// System.Collections.Generic.List`1[System.String]
3. 常用使用场景
A. 反射 (Reflection) 与 属性 (Attributes) 检查
这是 typeof 最频繁的舞台。用于在运行时检查某个类是否标记了特定的特性。
csharp
[Serializable]
public class DataModel { }
// 检查类是否拥有某个特性
bool isSerializable = typeof(DataModel).IsDefined(typeof(SerializableAttribute), false);
B. 依赖注入 (Dependency Injection) 注册
在 ASP.NET Core 或其他 DI 框架中,手动注册服务时必不可少。
csharp
services.AddScoped(typeof(IRepository<>), typeof(SqlRepository<>));
C. 泛型检查与比较
用于判断一个泛型参数的具体类型。
csharp
public void Process<T>(T item)
{
if (typeof(T) == typeof(int))
{
// 针对 int 的特殊优化逻辑
}
}
4. 注意事项
- 不要与
GetType()混淆 :typeof(T)是静态的,在编译时确定。obj.GetType()是动态的,在运行时根据实例的真实类型确定(涉及多态)。
- 泛型陷阱 :
typeof(List<>)获取的是未绑定参数的泛型原型(Unbound Generic Type)。typeof(List<int>)获取的是已绑定参数的具体类型。
- 变量名误用 :你不能对变量使用
typeof。例如int i = 0; typeof(i);是编译错误的,必须写成i.GetType()或typeof(int)。
5. typeof vs GetType() 决策流程

6. 核心区别对比
| 特性 | typeof | GetType() |
|---|---|---|
| 性质 | 运算符 (Operator) | 方法 (Method) |
| 解析时间 | 编译时 (Compile-time) | 运行时 (Runtime) |
| 操作对象 | 类型标识符 (Type Identifier) | 对象实例 (Object Instance) |
| 性能 | 极快(直接引用元数据) | 稍慢(需访问对象头信息) |
| 对 null 的反应 | 不受影响 | 抛出 NullReferenceException |
7. 示例
typeof 结合 反射 (Reflection) 调用私有方法
核心在于突破类的封装性
反射的本质是:绕过编译器,直接通过元数据操作内存中的方法表。
1. 实战代码:调用私有方法
假设我们有一个类,里面藏着一个私有方法:
csharp
public class SecuritySystem
{
private string EncryptData(string input)
{
return $"Encrypted: {input}";
}
}
我们要通过反射来"偷袭"这个私有方法:
csharp
using System.Reflection;
// 1. 获取类型信息 (静态提取)
Type type = typeof(SecuritySystem);
// 2. 创建实例 (反射调用通常需要一个对象实例)
object systemInstance = Activator.CreateInstance(type)!;
// 3. 核心步:找到私有方法
// BindingFlags 是关键,必须指定是非公开的 (NonPublic) 且是实例方法 (Instance)
MethodInfo? method = type.GetMethod("EncryptData",
BindingFlags.NonPublic | BindingFlags.Instance);
if (method != null)
{
// 4. 执行调用 (Invoke)
object? result = method.Invoke(systemInstance, new object[] { "TopSecret" });
Console.WriteLine(result); // 输出: Encrypted: TopSecret
}
2. 关键参数:BindingFlags 详解
调用 GetMethod 时,如果不传入正确的 绑定标志 (BindingFlags),反射将找不到私有成员:
BindingFlags.NonPublic:包含私有 (private) 和受保护的 (protected) 成员。BindingFlags.Instance:查找非静态成员。BindingFlags.Static:查找静态成员。BindingFlags.Public:查找公开成员(如果不传,默认只找公开的)。

3. 性能警告
作为资深开发者,我必须指出:反射很慢。
- 原因:每次调用都要进行字符串匹配(找方法名)、安全检查(是否有权访问)以及参数的装箱与拆箱。
- 优化策略 :如果你需要高频调用同一个私有方法,请不要重复执行
GetMethod。应该将MethodInfo存储在静态字段中缓存 起来,或者使用 委托 (Delegate) 进行预编译。
8. 易混淆
- 方法信息 (MethodInfo):.NET 提供的类,包含了方法的签名、返回类型、参数等所有细节。
- 绑定标志 (BindingFlags):用于过滤反射搜索结果的枚举。
- 执行调用 (Invoke):通过反射触发方法执行的动作。
- 激活器 (Activator):.NET 用于动态创建对象实例的工具类。
- 元数据 (Metadata):描述代码的数据(如类名、方法、参数类型等),存储在编译后的 DLL 文件中。
- 反射 (Reflection):在程序运行时观察、修改自身行为的能力。
- 未绑定泛型类型 (Unbound Generic Type) :指没有指定具体类型参数的泛型,如
Dictionary<,>。 - 程序集 (Assembly):.NET 编译生成的最小部署单元(.exe 或 .dll)。