C# CIL中的Stringbuilder(MSIL)

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<

我试图生成一段代码,该代码采用StringBuilder,并将类中所有属性的值写入字符串。我得到了以下内容,但我当前在以下代码中得到了一个“无效方法令牌”:

    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);
}