一、反射的应用场景
场景 1:插件系统
需求:开发一个支持动态加载插件的应用程序,插件以 DLL 文件形式提供,用户无需修改主程序即可扩展功能。
示例代码
csharp
using System;
using System.IO;
using System.Reflection;
public interface IPlugin
{
void Execute();
}
public class LoggerPlugin : IPlugin
{
public void Execute()
{
Console.WriteLine("Logging from plugin...");
}
}
class Program
{
static void Main()
{
// 假设插件 DLL 在 Plugins 文件夹
string pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins", "Plugin.dll");
// 加载程序集
Assembly pluginAssembly = Assembly.LoadFrom(pluginPath);
// 查找实现 IPlugin 的类型
foreach (Type type in pluginAssembly.GetTypes())
{
if (typeof(IPlugin).IsAssignableFrom(type) && !type.IsInterface)
{
// 创建插件实例并执行
IPlugin plugin = (IPlugin)Activator.CreateInstance(type);
plugin.Execute();
}
}
}
}
说明
- 反射作用:动态加载外部 DLL,检查类型并创建实例。
- 应用:类似 Visual Studio 的扩展机制,允许用户添加新功能(如日志、数据处理插件)。
场景 2:对象属性映射
需求:将一个类的属性值复制到另一个类,属性名相同但类型不同(如 DTO 和实体类之间的转换)。
示例代码
csharp
using System;
using System.Reflection;
public class Source
{
public string Name { get; set; } = "Alice";
public int Age { get; set; } = 25;
}
public class Destination
{
public string Name { get; set; }
public string Age { get; set; } // 类型不同
}
class Program
{
static void Main()
{
Source source = new Source();
Destination dest = MapProperties<Source, Destination>(source);
Console.WriteLine($"Name: {dest.Name}, Age: {dest.Age}");
}
static TDest MapProperties<TSource, TDest>(TSource source) where TDest : new()
{
TDest dest = new TDest();
Type sourceType = typeof(TSource);
Type destType = typeof(TDest);
foreach (PropertyInfo sourceProp in sourceType.GetProperties())
{
PropertyInfo destProp = destType.GetProperty(sourceProp.Name);
if (destProp != null && destProp.CanWrite)
{
object value = sourceProp.GetValue(source);
if (value != null)
{
// 类型转换
object convertedValue = Convert.ChangeType(value, destProp.PropertyType);
destProp.SetValue(dest, convertedValue);
}
}
}
return dest;
}
}
输出
Name: Alice, Age: 25
说明
- 反射作用:动态获取属性并映射值,支持类型转换。
- 应用:在 ORM(如 Entity Framework)或 API 数据传输中,将数据库实体映射到 DTO。
二、特性的应用场景
场景 1:数据验证
需求:在保存对象到数据库前,验证属性是否符合要求(如非空、长度限制)。
示例代码
csharp
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Property)]
public class RequiredAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Property)]
public class MaxLengthAttribute : Attribute
{
public int Length { get; }
public MaxLengthAttribute(int length) => Length = length;
}
public class User
{
[Required]
[MaxLength(10)]
public string Username { get; set; }
[Required]
public int Age { get; set; }
}
class Program
{
static void Main()
{
User user = new User { Username = "Alice1234567", Age = 0 };
string error = Validate(user);
Console.WriteLine(error ?? "验证通过");
}
static string Validate(object obj)
{
Type type = obj.GetType();
foreach (PropertyInfo prop in type.GetProperties())
{
// 检查 Required
if (prop.GetCustomAttribute<RequiredAttribute>() != null)
{
object value = prop.GetValue(obj);
if (value == null || (value is string str && string.IsNullOrEmpty(str)))
{
return $"{prop.Name} 不能为空";
}
}
// 检查 MaxLength
MaxLengthAttribute maxLength = prop.GetCustomAttribute<MaxLengthAttribute>();
if (maxLength != null && prop.PropertyType == typeof(string))
{
string value = (string)prop.GetValue(obj);
if (value != null && value.Length > maxLength.Length)
{
return $"{prop.Name} 长度不能超过 {maxLength.Length}";
}
}
}
return null;
}
}
输出
Username 长度不能超过 10
说明
- 特性作用:为属性添加验证规则,反射读取并执行验证。
- 应用 :类似 ASP.NET Core 的
[Required]
和[MaxLength]
,用于表单验证。
场景 2:权限控制
需求:根据用户角色动态控制方法是否可执行,例如只有管理员能调用某些功能。
示例代码
csharp
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method)]
public class RoleAttribute : Attribute
{
public string RequiredRole { get; }
public RoleAttribute(string role) => RequiredRole = role;
}
public class AdminService
{
[Role("Admin")]
public void DeleteUser()
{
Console.WriteLine("用户已删除");
}
[Role("User")]
public void ViewProfile()
{
Console.WriteLine("查看个人资料");
}
}
class Program
{
static void Main()
{
string currentRole = "User"; // 模拟当前用户角色
AdminService service = new AdminService();
// 尝试调用方法
CallMethod(service, "DeleteUser", currentRole);
CallMethod(service, "ViewProfile", currentRole);
}
static void CallMethod(object instance, string methodName, string userRole)
{
Type type = instance.GetType();
MethodInfo method = type.GetMethod(methodName);
RoleAttribute roleAttr = method.GetCustomAttribute<RoleAttribute>();
if (roleAttr != null && roleAttr.RequiredRole != userRole)
{
Console.WriteLine($"权限不足:{methodName} 需要 {roleAttr.RequiredRole} 角色");
return;
}
method.Invoke(instance, null);
}
}
输出
权限不足:DeleteUser 需要 Admin 角色
查看个人资料
说明
- 特性作用:标记方法的权限要求,反射检查角色并决定是否执行。
- 应用 :类似 ASP.NET 的
[Authorize(Roles = "Admin")]
,用于权限管理。
三、反射与特性结合的场景
场景:命令行参数解析
需求 :根据命令行参数动态调用带特性的方法,例如 --help
调用帮助方法。
示例代码
csharp
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method)]
public class CommandAttribute : Attribute
{
public string CommandName { get; }
public CommandAttribute(string name) => CommandName = name;
}
public class CommandHandler
{
[Command("help")]
public void ShowHelp()
{
Console.WriteLine("显示帮助信息");
}
[Command("run")]
public void RunApp()
{
Console.WriteLine("运行应用程序");
}
}
class Program
{
static void Main(string[] args)
{
string command = args.Length > 0 ? args[0] : "help";
CommandHandler handler = new CommandHandler();
foreach (MethodInfo method in typeof(CommandHandler).GetMethods())
{
CommandAttribute attr = method.GetCustomAttribute<CommandAttribute>();
if (attr != null && attr.CommandName == command)
{
method.Invoke(handler, null);
return;
}
}
Console.WriteLine("未知命令");
}
}
输出(运行 program.exe run
)
运行应用程序
说明
- 反射与特性结合:通过反射扫描方法,匹配特性中的命令名并执行。
- 应用 :类似命令行工具(如
dotnet
CLI)或脚本引擎。
总结
- 反射:适合动态加载(如插件)、对象映射(如 DTO 转换)。
- 特性:适合声明式配置(如验证、权限)。
- 结合使用:实现复杂的运行时逻辑(如命令解析、依赖注入)。
这些场景展示了反射和特性在实际开发中的强大能力。