InvalidProgramException: (wrapper dynamic-method) object:GetField () 中的无效 IL 代码: IL_0000: ret
InvalidProgramException: Invalid IL code in (wrapper dynamic-method) object:GetField (): IL_0000: ret
如标题所述。但是,我正在尝试这样做:
delegate char[] FieldDelegate();
private FieldDelegate Get_InternalBuffer(StringBuilder sb)
{
var sbType = sb.GetType();
var fieldInfo = sbType.GetField("m_ChunkChars",
BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
var dynMethod = new DynamicMethod("GetField", typeof(char[]), new Type[0], true);
ILGenerator ig = dynMethod.GetILGenerator();
ig.Emit(OpCodes.ldflda, fieldInfo);
ig.Emit(OpCodes.Ret);
return dynMethod.CreateDelegate(typeof(FieldDelegate)) as FieldDelegate;
}
短,我不知道为什么。我已经检查了 class 的 IL 代码,它只包含一个“char[] 缓冲区”来模拟我在这里所做的事情,它实际上正确地说明了这一点:“IL_0006: ret”作为一个 IL_instruction,那我做错了什么?
任何帮助都会很棒!
此致
我不是 100% 确定您要实现的实际目标是什么,但它是否必须是动态的/使用 Emit API?
如果不是,这里有一个有效的反射方法:
private static Func<char[]> Get_InternalBuffer_Reflection_Only(StringBuilder stringBuilder)
{
Type sbType = stringBuilder.GetType();
FieldInfo fieldInfo = sbType.GetField("m_ChunkChars",
BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
Func<char[]> func = () => (char[])fieldInfo.GetValue(stringBuilder);
return func;
}
有很多注意事项需要注意:
- 您正在捕获 Delegate/Func 内的
StringBuilder
,从而将其生命周期与返回的 Delegate/Func. 联系起来
- 每次要使用新的
StringBuilder
时,您都必须支付 emitting/reflection 的开销
编辑:
为了提高性能,我认为您可以使用 Expression 或 Emit 来实现。使用 IL,我不确定您如何在动态创建的方法中捕获 StringBuilder
参数,但您可以稍微改变您的委托以获得相同的结果。
再次查看您的代码,它不起作用的原因是因为您在调用 Ldfld
时方法中的堆栈上实际上没有任何内容。 FieldInfo
单独简单地描述了如何获取值,您仍然需要对对象的引用以从中检索值。
更改您的委托,您可以这样做:
delegate char[] FieldDelegate(StringBuilder sb);
private static FieldDelegate Get_InternalBuffer()
{
Type sbType = typeof(StringBuilder);
FieldInfo fieldInfo = sbType.GetField("m_ChunkChars",
BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
var dynMethod = new DynamicMethod("DynamicGetChunkChars",
typeof(char[]), new Type[] { sbType }, true);
ILGenerator ig = dynMethod.GetILGenerator();
ig.Emit(OpCodes.Ldarg_0);
ig.Emit(OpCodes.Ldfld, fieldInfo);
ig.Emit(OpCodes.Ret);
return dynMethod.CreateDelegate(typeof(FieldDelegate)) as FieldDelegate;
}
static void Main(string[] args)
{
var sb = new StringBuilder("test123");
FieldDelegate getBuffer = Get_InternalBuffer();
char[] ret = getBuffer(sb);
Console.ReadLine();
}
您必须使用 StringBuilder
调用返回的方法。
这也意味着您现在可以缓存返回的方法并重新使用它。
如标题所述。但是,我正在尝试这样做:
delegate char[] FieldDelegate();
private FieldDelegate Get_InternalBuffer(StringBuilder sb)
{
var sbType = sb.GetType();
var fieldInfo = sbType.GetField("m_ChunkChars",
BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
var dynMethod = new DynamicMethod("GetField", typeof(char[]), new Type[0], true);
ILGenerator ig = dynMethod.GetILGenerator();
ig.Emit(OpCodes.ldflda, fieldInfo);
ig.Emit(OpCodes.Ret);
return dynMethod.CreateDelegate(typeof(FieldDelegate)) as FieldDelegate;
}
短,我不知道为什么。我已经检查了 class 的 IL 代码,它只包含一个“char[] 缓冲区”来模拟我在这里所做的事情,它实际上正确地说明了这一点:“IL_0006: ret”作为一个 IL_instruction,那我做错了什么?
任何帮助都会很棒!
此致
我不是 100% 确定您要实现的实际目标是什么,但它是否必须是动态的/使用 Emit API?
如果不是,这里有一个有效的反射方法:
private static Func<char[]> Get_InternalBuffer_Reflection_Only(StringBuilder stringBuilder)
{
Type sbType = stringBuilder.GetType();
FieldInfo fieldInfo = sbType.GetField("m_ChunkChars",
BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
Func<char[]> func = () => (char[])fieldInfo.GetValue(stringBuilder);
return func;
}
有很多注意事项需要注意:
- 您正在捕获 Delegate/Func 内的
StringBuilder
,从而将其生命周期与返回的 Delegate/Func. 联系起来
- 每次要使用新的
StringBuilder
时,您都必须支付 emitting/reflection 的开销
编辑:
为了提高性能,我认为您可以使用 Expression 或 Emit 来实现。使用 IL,我不确定您如何在动态创建的方法中捕获 StringBuilder
参数,但您可以稍微改变您的委托以获得相同的结果。
再次查看您的代码,它不起作用的原因是因为您在调用 Ldfld
时方法中的堆栈上实际上没有任何内容。 FieldInfo
单独简单地描述了如何获取值,您仍然需要对对象的引用以从中检索值。
更改您的委托,您可以这样做:
delegate char[] FieldDelegate(StringBuilder sb);
private static FieldDelegate Get_InternalBuffer()
{
Type sbType = typeof(StringBuilder);
FieldInfo fieldInfo = sbType.GetField("m_ChunkChars",
BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
var dynMethod = new DynamicMethod("DynamicGetChunkChars",
typeof(char[]), new Type[] { sbType }, true);
ILGenerator ig = dynMethod.GetILGenerator();
ig.Emit(OpCodes.Ldarg_0);
ig.Emit(OpCodes.Ldfld, fieldInfo);
ig.Emit(OpCodes.Ret);
return dynMethod.CreateDelegate(typeof(FieldDelegate)) as FieldDelegate;
}
static void Main(string[] args)
{
var sb = new StringBuilder("test123");
FieldDelegate getBuffer = Get_InternalBuffer();
char[] ret = getBuffer(sb);
Console.ReadLine();
}
您必须使用 StringBuilder
调用返回的方法。
这也意味着您现在可以缓存返回的方法并重新使用它。