2009-10-20 9 views
5

StringBuilderを使用してクラス内のすべてのプロパティの値を文字列に書き込むコードを生成しようとしています。私は、次のを持っているが、私は現在、次のコードでは、「トークン無効なメソッド」を取得しています:CIL(MSIL)の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; 
    } 

任意のアイデア? ありがとうございます。

+0

(:これは、と等価を生成

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 

コメントする) –

答えて

5

値の種類(intなど)のプロパティはボクシングが必要です。または別のAppendオーバーロードを使用する必要があります。

また:

  • あなたは(arg0に)
  • StringBuilder.Appendが流暢なAPIであるオブジェクトを毎回ロードする必要があります。あなたが値をポップ、またはする必要があるのいずれかにそれを再利用:
  • を結果として、あなたがフィールドを必要としない

は(個人的に、しかし、私はstringを返すだろうが、「まあまあ」 )

ようなので:返信

StringBuilder ClassWriter(T obj) { 
    return new StringBuilder.Append((object)obj.Foo).Append((object)obj.Bar) 
        .Append((object)obj.Blip).Append((object)obj.Blap); 
} 
+0

+1、非常にうまく説明しました。 –

+0

ああ、ありがとう、これは超説明です! 私はあなたがボクシングの意味を参照して、私はコンパイラが自動的に正しいオーバーロードを解決するためにコールするために使用しています。 Appendが意味するものが流暢なAPIであるかどうかわかりませんが、追加されている値がスタックから消費されていないことを意味しますか? Ldarg_0はどこから入力されますか? すべての質問は申し訳ありませんが、流暢でxD – Josh

+2

と書いてありますが、Appendは 'void'を返さないことを意味します。あなたは '.Append(...)。Append(...)Append(...)'などを呼び出します。各呼び出しの後にスタックに値を残していました。 'arg0'は入力パラメータです(静的メソッドなので)。インスタンスメソッドの場合、 'arg0'は「this」です。 –