2012-10-12 43 views
5

Tôi đã đoạn mã sau C#:Emitting chức năng với tùy chọn tham số

public static double f(double x1, double x2 = 1) 
{ 
    return x1 * x2; 
} 

Và ở đây nó là IL mã (ILSpy):

.method public hidebysig static 
    float64 f (
     float64 x1, 
     [opt] float64 x2 
    ) cil managed 
{ 
    .param [2] = float64(1) 
    // Method begins at RVA 0x20c6 
    // Code size 4 (0x4) 
    .maxstack 8 

    IL_0000: ldarg.0 
    IL_0001: ldarg.1 
    IL_0002: mul 
    IL_0003: ret 
} // end of method A::f 

Làm thế nào tôi có thể nhận được nó với System.Reflection.Emit hoặc tốt hơn với Mono.Cecil?

Trả lời

4

Nếu tôi muốn thực hiện công cụ với Mono.Cecil Tôi thường tạo lớp/phương thức trong C# với mã mong muốn. Sau đó tôi kiểm tra nó (Hãy chắc chắn rằng bạn đang chạy nó trong chế độ phát hành) với Mono.Cecil và tái tạo nó.

Vì vậy, bạn cần có một MethodDefinition với thông số name, attributesreturnType. Tên: "f"

Các thuộc tính cho phương pháp của bạn sẽ là: Mono.Cecil.MethodAttributes.FamANDAssem | Mono.Cecil.MethodAttributes.Family | Mono.Cecil.MethodAttributes.Static | Mono.Cecil.MethodAttributes.HideBySig

Và kiểu trả về (kiểu Mono.Cecil.TypeReference như System.Double)

Đối với các thông số, có hai ParameterDefinition bạn có thể thêm với target.Parameters.Add()

một trong những thông số của bạn có giá trị mặc định để thuộc tính của nó phải Mono.Cecil.ParameterAttributes.Optional | Mono.Cecil.ParameterAttributes.HasDefaultConstant bộ của nó để 1.0 (trong trường hợp của bạn)

Bây giờ cho cơ thể phương pháp:

target.Body.GetILProcessor(); // target is your `MethodDefinition` object. 

Sau khi kiểm tra các hướng dẫn từ target.Body.Instructions, chúng ta thấy các mã sau:

IL_0000: ldarg.0 
IL_0001: ldarg.1 
IL_0002: mul 
IL_0003: stloc.0 
IL_0004: br.s IL_0007 
IL_0005: ldloc.0 
IL_0007: ret 

Vì vậy, chỉ cần thêm các mã trong chuỗi đúng

processor.Append(OpCodes.Ldarg_0); 

Sau đó, hãy tiêm/lưucủa bạn 0 đến hội đồng tương ứng.

đang thanh tra lắp ráp của tôi trông giống như sau:

private static void EnumerateAssembly(AssemblyDefinition assembly) 
     { 
      foreach (var module in assembly.Modules) 
      { 
       foreach (var type in module.GetAllTypes()) 
       { 
        foreach (var field in type.Fields) 
        { 
         Debug.Print(field.ToString()); 
        } 
        foreach (var method in type.Methods) 
        { 
         Debug.Print(method.ToString()); 
         foreach (var instruction in method.Body.Instructions) 
         { 
          Debug.Print(instruction.ToString()); 
         } 
        } 
       } 
      } 
     } 
+5

bạn không bao giờ nên cần phải thêm "nop". Nếu bạn đang nhìn thấy "nop", nó có nghĩa là (luôn luôn) bạn xây dựng trong chế độ gỡ lỗi hơn là chế độ phát hành, trước khi nhìn vào mã trong phản xạ/isdasm/bất cứ điều gì. Sẽ tốt hơn nếu kiểm tra IL từ một bản phát hành. –

+0

@MarcGravell Cảm ơn bạn đã đứng đầu! – Alex

+0

Tôi không chỉ biết về việc đặt Hằng số thành giá trị. Cảm ơn bạn anyway! –

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