C#反射是一种强大的工具,它允许开发者在运行时动态地检查和操作类型、方法、属性等。本文将详细介绍反射的基本用法以及其在架构设计中的实际应用。
类的反射
通过类名字符串创建类对象是反射的一个典型用例。以下代码展示了如何实现这一功能:
using System;
using System.Reflection;
public class ReflectionExample
{
public static void Execute()
{
string className = "Namespace.MyClass";
Type type = GetTypeFromAssembly(className);
MyClass instance = (MyClass)Activator.CreateInstance(type);
// 调用实例方法或访问属性
}
private static Type GetTypeFromAssembly(string fullName)
{
Assembly assembly = Assembly.Load("Namespace");
return assembly.GetType(fullName, true, false);
}
}
public class MyClass
{
public void PrintMessage()
{
Console.WriteLine("Hello from MyClass!");
}
}
上述代码中,`GetTypeFromAssembly` 方法加载了指定程序集,并通过完全限定名获取类型信息。随后使用 `Activator.CreateInstance` 创建该类型的实例。
方法的反射调用
除了创建对象外,反射还可以用于动态调用方法。以下示例展示了如何通过反射调用带有参数的方法:
public static void ExecuteMethod()
{
Assembly assembly = Assembly.Load("Namespace");
Type type = assembly.GetType("Namespace.MyClass", true, false);
MethodInfo method = type.GetMethod("PrintMessageWithParam");
object instance = assembly.CreateInstance("Namespace.MyClass");
object[] parameters = new object[] { "Test Message" };
method.Invoke(instance, parameters);
}
public class MyClass
{
public void PrintMessageWithParam(string message)
{
Console.WriteLine(message);
}
}
在此示例中,我们首先定位到目标方法,然后创建类的实例并调用该方法,同时传递所需参数。
属性的反射访问
反射同样可以用来访问类的属性值。下面是一个简单的例子:
public static object GetProperty(object obj, string propertyName)
{
Type type = obj.GetType();
PropertyInfo property = type.GetProperty(propertyName);
if (property != null)
{
return property.GetValue(obj, null);
}
return null;
}
public class MyClass
{
public string Name { get; set; }
}
// 使用示例
MyClass myInstance = new MyClass { Name = "Sample" };
object nameValue = GetProperty(myInstance, "Name");
Console.WriteLine(nameValue); // 输出: Sample
反射在框架设计中的应用
反射常被用于构建灵活的框架。例如,一个基于命令模式的简单框架可能如下所示:
public abstract class CommandBase { }
public class GetNameCommand : CommandBase { }
public interface ICommandHandler<T> where T : CommandBase
{
ResultBase Handle(T command);
}
public class GetNameCommandHandler : ICommandHandler<GetNameCommand>
{
public ResultBase Handle(GetNameCommand command)
{
return new ResultBase { Message = "Handled!" };
}
}
public class Proxy
{
public ResultBase ExecuteCommand(CommandBase command)
{
string handlerTypeName = command.GetType().Name + "Handler";
string namespaceName = command.GetType().Namespace;
Assembly assembly = Assembly.Load(namespaceName);
Type handlerType = assembly.GetType($"{namespaceName}.{handlerTypeName}");
object handlerInstance = Activator.CreateInstance(handlerType);
MethodInfo handleMethod = handlerType.GetMethod("Handle");
return (ResultBase)handleMethod.Invoke(handlerInstance, new[] { command });
}
}
public class ResultBase
{
public string Message { get; set; }
}
在这个例子中,`Proxy` 类根据传入的命令类型动态查找并调用相应的处理器。
反射与特性的结合
反射经常与特性(Attribute)一起使用以简化复杂逻辑。例如,清除特定标记的属性值:
[Clearable]
public string ClearMe { get; set; }
public void ClearAttributes(object obj)
{
var properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
var attributes = property.GetCustomAttributes(typeof(ClearableAttribute), false);
if (attributes.Length > 0)
{
property.SetValue(obj, null);
}
}
}
[AttributeUsage(AttributeTargets.Property)]
public class ClearableAttribute : Attribute { }
总结
反射虽然强大,但应谨慎使用以避免性能问题。合理利用反射可以显著提升代码的灵活性和可维护性。