跟着AI学习C# Day20
反射与特性是C#中的高级特性。反射允许在运行时动态获取类型信息、创建对象和调用方法,常用于插件系统、序列化等场景。特性则为代码元素添加元数据,可通过反射读取。文章介绍了反射的基本用法(获取类型、创建实例、调用方法)、性能优化建议,以及如何定义和使用自定义特性。最后通过一个插件系统实例展示了如何结合反射与特性实现动态加载和执行功能。这些技术在框架开发、测试工具等领域有广泛应用,是C#高级编程的重要部
·
📅 Day 20:反射与特性(Reflection & Attributes)
✅ 学习目标:
- 理解什么是 反射(Reflection) 及其作用;
- 掌握如何使用反射动态获取类型信息、创建对象和调用方法;
- 理解 特性(Attributes) 是什么及其用途;
- 学会定义和使用自定义特性;
- 能够结合反射与特性实现插件系统、序列化器或自动注册功能;
- 编写一个使用反射加载程序集并执行方法的示例。
🧠 一、什么是反射(Reflection)?
反射(Reflection) 是 .NET 提供的一种机制,允许你在运行时动态地分析、检查和操作程序集中的类型(如类、接口、方法、属性等)。
常见用途:
场景 | 示例 |
---|---|
自动测试工具 | 使用反射查找所有测试类和方法 |
序列化/反序列化 | 动态读取对象属性进行 JSON 映射 |
插件系统 | 动态加载 DLL 并调用其中的方法 |
依赖注入容器 | 根据类型自动解析构造函数参数 |
🔍 二、反射常用功能
获取类型信息
Type type = typeof(string);
Console.WriteLine("类型名称:" + type.FullName);
获取对象的运行时类型
object obj = "Hello";
Type runtimeType = obj.GetType();
创建对象实例
Type type = typeof(string);
object instance = Activator.CreateInstance(type);
注意:对于有参数的构造函数,需要传递参数数组。
获取和调用方法
MethodInfo method = type.GetMethod("MethodName", new[] { typeof(int) });
method.Invoke(instance, new object[] { 42 });
获取属性和字段
PropertyInfo prop = type.GetProperty("Name");
prop.SetValue(instance, "张三");
object value = prop.GetValue(instance);
⚙️ 三、反射性能优化建议
反射虽然强大,但性能较低。以下是一些优化方式:
方法 | 说明 |
---|---|
Expression Trees |
构建委托缓存以提高重复调用性能 |
Delegate.CreateDelegate |
将 MethodInfo 转换为委托 |
缓存反射结果 |
避免重复调用 GetMethod / GetProperty |
🎯 四、什么是特性(Attribute)?
特性(Attribute) 是一种元数据机制,用于向代码元素(如类、方法、属性)附加额外的信息。
这些信息可以在编译时或运行时通过反射读取。
🧩 五、内置特性示例
特性 | 说明 |
---|---|
[Obsolete] |
标记某个方法已过时 |
[Serializable] |
表示该类可被序列化 |
[DllImport] |
用于调用非托管 DLL 函数 |
[Conditional] |
控制方法是否在特定条件下编译 |
示例:
[Obsolete("请使用 NewMethod 替代")]
public void OldMethod()
{
// ...
}
🧱 六、自定义特性(Custom Attribute)
你可以定义自己的特性类,继承 Attribute
:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class AuthorAttribute : Attribute
{
public string Name { get; }
public AuthorAttribute(string name)
{
Name = name;
}
}
然后应用到类或方法上:
[Author("李四")]
public class MyService
{
[Author("王五")]
public void DoWork()
{
// ...
}
}
🔍 七、通过反射读取特性
Type type = typeof(MyService);
// 获取类上的特性
foreach (var attr in type.GetCustomAttributes(false))
{
if (attr is AuthorAttribute author)
{
Console.WriteLine($"类作者:{author.Name}");
}
}
// 获取方法上的特性
MethodInfo method = type.GetMethod("DoWork");
foreach (var attr in method.GetCustomAttributes(true))
{
if (attr is AuthorAttribute author)
{
Console.WriteLine($"方法作者:{author.Name}");
}
}
💪 实战练习:构建一个基于特性和反射的插件系统
功能要求:
- 定义一个插件接口;
- 使用特性标记插件类;
- 使用反射扫描程序集,找到所有插件类;
- 动态创建实例并调用方法。
示例代码结构:
public interface IPlugin
{
void Execute();
}
[AttributeUsage(AttributeTargets.Class)]
public class PluginAttribute : Attribute { }
[Plugin]
public class HelloPlugin : IPlugin
{
public void Execute()
{
Console.WriteLine("你好,插件!");
}
}
class Program
{
static void Main()
{
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
{
if (type.GetCustomAttributes(typeof(PluginAttribute), false).Length > 0 &&
typeof(IPlugin).IsAssignableFrom(type))
{
var plugin = (IPlugin)Activator.CreateInstance(type);
plugin.Execute();
}
}
}
}
📝 小结
今天你学会了:
- 什么是 反射(Reflection),它在运行时的作用;
- 如何使用反射动态获取类型信息、创建实例、调用方法;
- 了解了 特性(Attribute) 的概念和用途;
- 学会定义和使用自定义特性;
- 掌握了如何结合反射与特性实现插件系统、自动注册等功能;
- 编写了一个完整的基于反射与特性的插件系统示例。
反射与特性是 C# 中非常强大的两个机制,它们广泛应用于框架开发、自动化测试、ORM 工具、DI 容器等领域。
🧩 下一步学习方向(Day 21)
明天我们将进入一个新的主题 —— 动态类型与动态语言运行时(Dynamic Types & DLR),你将学会如何使用 dynamic
类型简化反射操作,并理解它背后的原理。
更多推荐
所有评论(0)