问题描述
如标题中所述。但是,我正在尝试这样做:
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;
}
简短地说,我不知道为什么。我已经检查了仅包含“ char []缓冲区”的类的IL代码,以模拟我在此处执行的操作,它实际上正确地指出了这一点:“ IL_0006:ret”作为单个IL_instruction,所以我在做什么错了? / p>
任何帮助都会很棒!
最诚挚的问候
解决方法
我不确定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;
}
有很多注意事项:
- 您正在将
StringBuilder
捕获到Delegate / Func中,并将其生命周期与返回的Delegate / Func联系起来。 - 每次使用新的
StringBuilder
时,您都必须支付发射/反射的开销
编辑:
为了提高性能,我认为您可以使用Expression或Emit做到这一点。使用IL时,我不确定如何在动态创建的方法中捕获StringBuilder
参数,但是可以稍微更改Delegate以获得相同的结果。
再次查看代码之所以不起作用,是因为您在调用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
调用返回的方法。
这也意味着您现在可以缓存返回的方法并重复使用。