C# CIL中的Stringbuilder(MSIL)
我试图生成一段代码,该代码采用StringBuilder,并将类中所有属性的值写入字符串。我得到了以下内容,但我当前在以下代码中得到了一个“无效方法令牌”:C# CIL中的Stringbuilder(MSIL),c#,token,cil,dynamicmethod,C#,Token,Cil,Dynamicmethod,我试图生成一段代码,该代码采用StringBuilder,并将类中所有属性的值写入字符串。我得到了以下内容,但我当前在以下代码中得到了一个“无效方法令牌”: public static DynamicAccessor<T> CreateWriter(T target) //Target class to *serialize* { DynamicAccessor<T> dynAccessor = new DynamicAccessor<
public static DynamicAccessor<T> CreateWriter(T target) //Target class to *serialize*
{
DynamicAccessor<T> dynAccessor = new DynamicAccessor<T>();
MethodInfo AppendMethod = typeof(StringBuilder).GetMethod("Append", new[] { typeof(Object) }); //Append method of Stringbuilder
var method = new DynamicMethod("ClassWriter", typeof(StringBuilder), new[] { typeof(T) }, typeof(T), true);
var generator = method.GetILGenerator();
LocalBuilder sb = generator.DeclareLocal(typeof(StringBuilder)); //sb pointer
generator.Emit(OpCodes.Newobj, typeof(StringBuilder)); //make our string builder
generator.Emit(OpCodes.Stloc, sb); //make a pointer to our new sb
//iterate through all the instance of T's props and sb.Append their values.
PropertyInfo[] props = typeof(T).GetProperties();
foreach (var info in props)
{
generator.Emit(OpCodes.Callvirt, info.GetGetMethod()); //call the Getter
generator.Emit(OpCodes.Ldloc, sb); //load the sb pointer
generator.Emit(OpCodes.Callvirt, AppendMethod); //Call Append
}
generator.Emit(OpCodes.Ldloc, sb);
generator.Emit(OpCodes.Ret); //return pointer to sb
dynAccessor.WriteHandler = method.CreateDelegate(typeof(Write)) as Write;
return dynAccessor;
}
publicstaticdynamicaccessor CreateWriter(T target)//要*序列化的目标类*
{
DynamicAccessor dynacessor=新的DynamicAccessor();
MethodInfo AppendMethod=typeof(StringBuilder).GetMethod(“Append”,新[]{typeof(Object)});//StringBuilder的Append方法
var方法=新的DynamicMethod(“ClassWriter”,typeof(StringBuilder),new[]{typeof(T)},typeof(T),true);
var生成器=方法.GetILGenerator();
LocalBuilder sb=generator.DeclareLocal(typeof(StringBuilder));//sb指针
Emit(OpCodes.Newobj,typeof(StringBuilder));//生成我们的字符串生成器
Emit(OpCodes.Stloc,sb);//创建指向新sb的指针
//遍历T的道具和sb的所有实例。附加它们的值。
PropertyInfo[]props=typeof(T).GetProperties();
foreach(道具中的var信息)
{
generator.Emit(OpCodes.Callvirt,info.getMethod());//调用Getter
generator.Emit(OpCodes.Ldloc,sb);//加载sb指针
generator.Emit(OpCodes.Callvirt,AppendMethod);//调用Append
}
生成器.Emit(操作码.Ldloc,sb);
generator.Emit(OpCodes.Ret);//返回指向sb的指针
dynacessor.WriteHandler=method.CreateDelegate(typeof(Write))作为Write;
返回式动态传感器;
}
有什么想法吗?
提前感谢:)任何值类型的属性(
int
等)都需要装箱;或者,您需要使用不同的附加重载
此外:
- 每次都需要加载对象(arg0)
StringBuilder.Append
是一个流畅的API;您需要弹出该值,或者重新使用它:
- 因此,您不需要字段
(但就个人而言,我会返回一个字符串,但是“meh”)
像这样:
DynamicAccessor<T> dynAccessor = new DynamicAccessor<T>();
MethodInfo AppendMethod = typeof(StringBuilder).GetMethod("Append", new[] { typeof(Object) }); //Append method of Stringbuilder
var method = new DynamicMethod("ClassWriter", typeof(StringBuilder), new[] { typeof(T) }, typeof(T), true);
var generator = method.GetILGenerator();
generator.Emit(OpCodes.Newobj, typeof(StringBuilder).GetConstructor(Type.EmptyTypes)); //make our string builder
//iterate through all the instance of T's props and sb.Append their values.
PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var info in props)
{
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Callvirt, info.GetGetMethod()); //call the Getter
if (info.PropertyType.IsValueType)
{
generator.Emit(OpCodes.Box, info.PropertyType);
}
generator.Emit(OpCodes.Callvirt, AppendMethod); //Call Append
}
generator.Emit(OpCodes.Ret); //return pointer to sb
啊,谢谢,这是一个超级解释!我明白你所说的装箱是什么意思了,我习惯于编译器自动解析要调用的正确重载。我不确定你所说的Append是一个流畅的API,这是否意味着被追加的值没有从堆栈中被消耗?Ldarg_0从何处获取输入?很抱歉,我的意思是Append不会返回void
——它返回this
;调用.Append(…).Append(…).Append(…)
等。每次调用后都在堆栈上留下一个值arg0
是输入参数(因为这是一个静态方法)。对于实例方法,arg0
是“this”。
StringBuilder ClassWriter(T obj) {
return new StringBuilder.Append((object)obj.Foo).Append((object)obj.Bar)
.Append((object)obj.Blip).Append((object)obj.Blap);
}