详解 C# 反射(Reflection)
C# 反射(Reflection)是指在程序运行的时候动态的获得一个类的信息以及可以操作这个类、实例等相关信息的能力。反射提供了一种机制来检查程序集中的元数据,包括类型定义、字段、属性、方法等信息。在运行时,可以通过反射来创建对象、调用方法、获取或设置属性等。
反射的作用
- 可以查看类型、方法、构造函数、属性、字段、事件等信息。
- 可以在运行时动态创建类型、访问对象及方法,对程序性能会有一些损失。
- 可以使代码更灵活,通过反射可以动态调用未知对象的方法、赋值未知对象的属性等。
反射的基本用法
下面以一个简单的示例演示反射的基本用法:
using System.Reflection;
// 引用程序集
Assembly assembly = Assembly.Load("MyAssembly.dll");
// 获取类信息
Type type = assembly.GetType("MyNamespace.MyClass");
// 创建类实例
object obj = Activator.CreateInstance(type);
// 调用方法
MethodInfo method = type.GetMethod("MyMethod");
method.Invoke(obj, null);
本示例演示了以下几个步骤:
- 引用 MyAssembly.dll 程序集。
- 获取 MyNamespace.MyClass 类型的信息。
- 创建该类的实例。
- 反射调用 MyClass.MyMethod 方法。
在使用反射时,需要引用目标程序集,并使用 Assembly 类来加载程序集。然后使用 GetType 方法获取类型信息,使用 Activator 类的 CreateInstance 方法创建实例,再使用 MethodInfo 类获取方法信息并调用 Invoke 方法执行目标方法。
反射的高级应用
除了基本用法之外,反射还有很多高级应用,如动态代理、序列化、调试等。下面以两个示例说明反射的高级应用:
动态代理
动态代理是指在程序运行时动态创建一个代理实例,代理实例在调用目标方法时,会先调用特定的方法进行预处理,接着将调用传递给具体的目标对象,并在调用后进行后处理。动态代理可以用来实现 AOP(面向切面编程)。
using System;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;
// 创建代理
MyClass proxy = (MyClass)new MyProxy(typeof(MyClass)).GetTransparentProxy();
// 调用目标方法
proxy.MyMethod();
// 自定义代理类
public class MyProxy : RealProxy
{
private Type targetType;
public MyProxy(Type targetType) : base(targetType)
{
this.targetType = targetType;
}
public override IMessage Invoke(IMessage msg)
{
// 执行前置处理
Console.WriteLine("Before call...");
// 调用目标方法
IMethodCallMessage callMsg = (IMethodCallMessage)msg;
object returnValue = null;
Exception exception = null;
try
{
MethodInfo method = targetType.GetMethod(callMsg.MethodName);
if (method == null)
{
throw new MissingMethodException(targetType.FullName, callMsg.MethodName);
}
returnValue = method.Invoke(GetUnwrappedServer(), callMsg.Args);
}
catch (Exception ex)
{
exception = ex;
}
// 执行后置处理
Console.WriteLine("After call...");
// 返回结果
return new ReturnMessage(returnValue, null, 0, null, callMsg);
}
private object GetUnwrappedServer()
{
return GetTransparentProxy();
}
}
// 目标类
public class MyClass
{
public void MyMethod()
{
Console.WriteLine("MyMethod called.");
}
}
本示例演示了以下几个步骤:
- 创建 MyProxy 代理类,重载 Invoke 方法对代理进行处理。
- 使用 GetTransparentProxy 方法获取代理实例。
- 调用代理的 MyMethod 方法。
- 在代理的 Invoke 方法中调用目标对象的方法并处理前后置任务。
序列化
通过反射,我们可以在运行时通过代码动态的创建对象,同时也能够序列化和反序列化对象。
using System;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
// 创建对象
MyClass obj = new MyClass();
// 序列化对象
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, obj);
// 反序列化对象
stream.Position = 0;
MyClass newObj = (MyClass)formatter.Deserialize(stream);
// 目标类
[Serializable]
public class MyClass
{
public void MyMethod()
{
Console.WriteLine("MyMethod called.");
}
}
本示例演示了以下几个步骤:
- 创建 MyClass 对象。
- 使用 BinaryFormatter 对象进行对象的序列化操作。
- 反序列化对象并获取对象信息。
反射的注意事项
尽管反射提供了很多便利,但是在实际应用中,也需要注意一些问题:
- 反射操作会降低程序性能,建议仅在必要时使用反射。
- 实际应用中,需要检查反射对象的值是否为 null。
- 直接操作反射对象可能会导致错误,需要加入异常处理的机制。
以上就是 C# 反射(Reflection)的详细攻略,希望对大家有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解C# 反射(Reflection) - Python技术站