2012-06-22 43 views
21

Nhiều phương pháp trong BCL được đánh dấu bằng thuộc tính [MethodImpl(MethodImplOptions.InternalCall)]. Điều này indicates rằng "phương pháp được thực hiện trong thời gian chạy ngôn ngữ chung".Điểm của MethodImplOptions.InternalCall là gì?

Điểm thiết kế khung theo cách này là gì đối với các hướng dẫn CIL rõ ràng rằng thời gian chạy sẽ bị buộc thực hiện? Cuối cùng, thuộc tính này đang tạo ra các nghĩa vụ hợp đồng cho thời gian chạy, nhưng theo một cách mà tôi có vẻ khó hiểu và không rõ ràng ngay lập tức.

Ví dụ, Math.Pow có thể đã được viết theo cách này (xin lỗi hỗn hợp không chính thức của tôi về C# + IL và IL chính nó nếu nó là xấu, điều này chỉ là một mẫu để giải thích quan điểm của tôi):

public static double Pow(double x, double y) 
{ 
    ldarg.0 
    ldarg.1 
    pow // Dedicated CIL instruction 
    ret 
} 

thay vì cách hiện tại:

[MethodImpl(MethodImplOptions.InternalCall)] 
public static double Pow(double x, double y); 

Tại sao MethodImplOptions.InternalCall tồn tại?

+6

Nó không phải như vậy không thể làm việc, nó chỉ quy mô khủng khiếp. Các giao dịch stack là tiềm ẩn cho các opcodes IL, rất nhiều công cụ sẽ phải được cập nhật để xử lý các chữ ký hàm. Nó miễn phí khi tờ khai nằm trong siêu dữ liệu. Và dễ dàng mở rộng vượt ra ngoài tiêu chuẩn Ecma-335. –

+0

@Hans: là câu hỏi về việc thêm hỗ trợ cho các hướng dẫn IL mới? Tôi hiểu rằng Ani muốn biết tại sao phương pháp 'InternalCall' lại ở đó ngay từ đầu. Chỉ cần hỏi ... –

+1

@thecoon - '// Hướng dẫn CIL chuyên dụng' là một gợi ý tốt. –

Trả lời

7

Tôi nghĩ rằng một lý do lớn là khó tạo ra một hướng dẫn IL mới và nó có thể ảnh hưởng đến rất nhiều công cụ, bao gồm các công cụ bên ngoài (ILGenerator, ilasm, ildasm, PEVerify, Reflector, PostSharp,…).

Nhưng tạo phương thức InternalCall mới? Đó là gần như đơn giản như viết phương pháp trong C# (Tôi giả sử, tôi đã không nhìn vào Rotor để xác minh) và nó không ảnh hưởng đến bất cứ điều gì.

Và nó không chỉ là tạo ra nó, tôi nghĩ rằng cùng áp dụng cho bảo trì.

+0

Xin lỗi, tôi đã đăng nhận xét nhưng bạn đã trả lời đúng, +1. –

+0

@svick: Đủ công bằng. Làm thế nào bạn sẽ giải thích Math.Pow được xung quanh kể từ khi phát hành đầu tiên của NET mặc dù? Liệu điểm của Hans không muốn làm quá phức tạp tiêu chuẩn ECMA là lý do? – Ani

+0

@Ani Nó vẫn sẽ có nghĩa là làm việc nhiều hơn cho hầu hết mọi người làm bất cứ điều gì với IL. Thực tế là công việc đó sẽ phải đi vào phiên bản đầu tiên của các công cụ không thay đổi nhiều. – svick

3

Tôi nghĩ rằng nó không phải là quá phức tạp CLR. Khi tôi lần đầu tiên nhìn vào CIL, tôi không thể không chú ý đến những điểm tương đồng với ngôn ngữ lắp ráp, và hơn thế nữa, các hướng dẫn giới hạn được thiết lập, gần như là họ đã làm cho nó chạy trực tiếp trên một bộ xử lý. Theo lý thuyết, khi mã của mẫu JIT của CLR cho Pow mà bạn đưa vào trong bài đăng của bạn, nó sẽ phải tự phát hành mã gốc cho hướng dẫn pow, vì không có hướng dẫn gốc (hoặc là nó chưa? cập nhật với các tập lệnh x86 mới kể từ vài năm trở lại). Nhìn từ quan điểm thực hiện của xem nhưng cũng từ quan điểm thực hiện của xem, nó là dễ dàng hơn nhiều để chỉ cần gọi vào mscorlib cho mã pow, hơn là chỉ "dán" nó nội tuyến.

Hoặc, họ có thể đã có bảng tra cứu các hàm mscorlib phổ biến là InternalCall và thay thế hướng dẫn bằng một cuộc gọi đến chính hàm đó. Nhưng sau đó một lần nữa, không phải tất cả InternalCall đều dễ như vậy.

Tôi nghĩ rằng đó là sự cân bằng để thuận tiện; cả hai bên của họ, cho CLR bảo trì, một tiêu chuẩn CLI thống nhất hơn và cho phép một số linh hoạt cho người gọi.

Điểm mấu chốt là tôi chưa phát triển CLR và điều này chỉ nằm ngoài đỉnh đầu của tôi. Điều tôi đã làm, tôi đoán vậy.

1

Phương thức này là bản địa, TRULY nguyên bản, được triển khai trong chính Thời gian chạy. Đừng quên, CLR đó đến từ C++ sau tất cả. Nó giống như trong trình biên dịch. Trong thế giới thực, CIL không thực sự thực thi. Đó là JIT-ted và sau đó được thực hiện, giống như một trình biên dịch, bởi thời gian chạy C/C++. Math.Pow là hầu hết có thể [đầu cơ] một cuộc gọi vào phương thức toán học c/C++ bản địa C/C++, và nó được thực hiện xác định - bây giờ NET và Mono thực hiện CLR.

Trong UnityEngine.dll, [MethodImpl(MethodImplOptions.InternalCall)] được sử dụng trên hầu hết các phương pháp bên ngoài gốc. Tuy nhiên, các phương thức C++ này sử dụng Thư viện CLR Mono C++ trực tiếp và chúng có thể hợp tác với C# theo cách thân mật hơn P/INVOKE. Và cách thực hiện nhiều hơn (PInvoke ẩn một số chi tiết thực hiện và làm cho một số khó hiểu)

Tuy nhiên, cách duy nhất để sử dụng [MethodImpl(MethodImplOptions.InternalCall)] là nếu bạn là bản thân CLR - tôi chỉ thử Mono như thế này. Tôi không biết nếu nó thậm chí có thể thay đổi thực hiện CLR của Microsoft, nhưng với Mono bạn được tự do lạm dụng tính năng này.

Ngoài ra, đừng làm phiền điều này với [MethodImpl(MethodImplOptions.Unmanaged)] - đó là toàn bộ câu chuyện khác nhau.

Thông tin thêm về các cuộc gọi nội bộ và làm thế nào Mono hoạt động, ở đây: http://www.mono-project.com/docs/advanced/embedding/

Disclaimer: Tôi không liên quan đến Unity hoặc Mono!