c#的反射和特性的应用场景

发布于:2025-03-28 ⋅ 阅读:(21) ⋅ 点赞:(0)

一、反射的应用场景

场景 1:插件系统

需求:开发一个支持动态加载插件的应用程序,插件以 DLL 文件形式提供,用户无需修改主程序即可扩展功能。

示例代码
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 和实体类之间的转换)。

示例代码
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:数据验证

需求:在保存对象到数据库前,验证属性是否符合要求(如非空、长度限制)。

示例代码
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:权限控制

需求:根据用户角色动态控制方法是否可执行,例如只有管理员能调用某些功能。

示例代码
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 调用帮助方法。

示例代码
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 转换)。
  • 特性:适合声明式配置(如验证、权限)。
  • 结合使用:实现复杂的运行时逻辑(如命令解析、依赖注入)。

这些场景展示了反射和特性在实际开发中的强大能力。