动态方法(DynamicMethod)是C#反射机制中的一部分,允许在运行时动态生成和执行代码,而不需要创建动态程序集或动态类型。这在需要高性能反射操作或需要动态生成代码的场景中非常有用。
using System;
using System.Reflection;
using System.Reflection.Emit;
public class DynamicFieldGetter
{
public static Func<object, object> CreateFieldGetter(FieldInfo fieldInfo)
{
// 创建动态方法
DynamicMethod dynamicMethod = new DynamicMethod(
name: $"Get_{fieldInfo.Name}",
returnType: typeof(object),
parameterTypes: new[] { typeof(object) },
restrictedSkipVisibility: true);
// 获取IL生成器
ILGenerator il = dynamicMethod.GetILGenerator();
// 加载参数(对象实例)
il.Emit(OpCodes.Ldarg_0);
// 如果是静态字段,不需要加载实例
if (!fieldInfo.IsStatic)
{
// 如果字段是值类型,需要拆箱
if (fieldInfo.DeclaringType.IsValueType)
{
il.Emit(OpCodes.Unbox, fieldInfo.DeclaringType);
}
else
{
il.Emit(OpCodes.Castclass, fieldInfo.DeclaringType);
}
}
// 获取字段值
il.Emit(fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, fieldInfo);
// 如果字段是值类型,需要装箱
if (fieldInfo.FieldType.IsValueType)
{
il.Emit(OpCodes.Box, fieldInfo.FieldType);
}
// 返回结果
il.Emit(OpCodes.Ret);
// 创建并返回委托
return (Func<object, object>)dynamicMethod.CreateDelegate(typeof(Func<object, object>));
}
}
public class TestClass
{
public string Name = "Test";
public int Age = 25;
public static double PI = 3.14159;
}
class Program
{
static void Main()
{
// 获取字段信息
FieldInfo nameField = typeof(TestClass).GetField("Name");
FieldInfo ageField = typeof(TestClass).GetField("Age");
FieldInfo piField = typeof(TestClass).GetField("PI");
// 创建动态getter
var getName = DynamicFieldGetter.CreateFieldGetter(nameField);
var getAge = DynamicFieldGetter.CreateFieldGetter(ageField);
var getPi = DynamicFieldGetter.CreateFieldGetter(piField);
// 创建测试实例
var testObj = new TestClass();
// 使用动态getter
Console.WriteLine(getName(testObj)); // 输出: Test
Console.WriteLine(getAge(testObj)); // 输出: 25
Console.WriteLine(getPi(null)); // 输出: 3.14159 (静态字段)
}
}
原因:默认情况下,动态方法只能访问公共成员
解决:在创建DynamicMethod时设置restrictedSkipVisibility
为true
new DynamicMethod(..., restrictedSkipVisibility: true);
原因:值类型需要特殊处理,包括拆箱和装箱
解决:在IL生成时添加适当的拆箱/装箱指令
if (fieldInfo.DeclaringType.IsValueType)
{
il.Emit(OpCodes.Unbox, fieldInfo.DeclaringType);
}
if (fieldInfo.FieldType.IsValueType)
{
il.Emit(OpCodes.Box, fieldInfo.FieldType);
}
原因:静态字段不需要实例参数
解决:在IL生成时区分静态和非静态字段
il.Emit(fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, fieldInfo);
动态方法生成的getter比直接反射快约20-50倍,接近直接字段访问速度。但第一次创建动态方法时有JIT编译开销,适合频繁调用的场景。
没有搜到相关的文章