2009-10-20 59 views
5

Tôi đang cố gắng tạo mã có một StringBuilder và ghi các giá trị của tất cả các thuộc tính trong một lớp vào một chuỗi. Tôi có các thông tin sau, nhưng hiện tại tôi đang nhận được "Mã thông báo phương thức không hợp lệ" trong mã sau:Trình xây dựng chuỗi trong CIL (MSIL)

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

Bất kỳ ý tưởng nào? Cảm ơn trước :)

+0

(trả lời để bình luận) –

Trả lời

5

Bất kỳ thuộc tính nào là loại giá trị (int v.v.) sẽ cần đấm bốc; hoặc bạn sẽ cần sử dụng quá tải khác nhau Append.

Ngoài ra:

  • bạn cần phải tải các đối tượng mỗi lần (arg0)
  • StringBuilder.Append là một API thông thạo; bạn có cần phải bật giá trị, hoặc tái sử dụng nó:
  • do đó, bạn không cần phải lĩnh vực này

(cá nhân, tuy nhiên, tôi muốn trả lại một string, nhưng "meh")

Giống như vậy:

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 

này tạo ra tương đương với:

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, được giải thích rất độc đáo. –

+0

Ah cảm ơn, đây là một lời giải thích siêu! Tôi hiểu ý của bạn là gì, bạn nên sử dụng trình biên dịch tự động giải quyết quá tải chính xác để gọi. Tôi không chắc chắn ý của bạn là gì bởi Append là một API thông thạo, điều đó có nghĩa là giá trị được thêm vào không bị tiêu thụ từ ngăn xếp? Và Ldarg_0 lấy đâu từ đâu? Xin lỗi cho tất cả các câu hỏi xD – Josh

+2

bởi thông thạo, tôi có nghĩa là Append không trả về 'void' - nó trả về' this'; bạn gọi '.Append (...). Append (...). Append (...)' vv Bạn đã để lại một giá trị trên stack sau mỗi cuộc gọi. 'arg0' là tham số đầu vào (vì đây là phương thức tĩnh). Đối với một phương thức instance, 'arg0' là" this ". –

Các vấn đề liên quan