2010-08-10 38 views
6

Có đúng là một phương thức thể hiện có thể được gọi trên tham chiếu null trong IL ..? Có ví dụ nào để thể hiện điều này không?Phương pháp gọi hàm trên tham chiếu null trong IL

+0

Chắc chắn điều này là không thể - bạn sẽ thực hiện phương pháp nào đối với trường hợp nào? –

+2

@Adam: rất có thể với một chút tin tặc IL. Mã này vẫn có thể xác minh 100%, nhưng trình biên dịch C# sẽ không bao giờ phát ra mã như vậy. – leppie

+0

Đủ công bằng, làm thế nào nó nhận được từ tham chiếu null và chuyển hướng đến đúng cá thể trong bộ nhớ? Ví dụ: nếu phương thức sửa đổi trạng thái nội bộ. –

Trả lời

10

Có, điều này là có thể, miễn là phương pháp không sử dụng this vì CLR không thực hiện kiểm tra trống cho các hướng dẫn call.

Bạn sẽ phải sửa đổi IL bằng tay vì trình biên dịch C# hầu như luôn tạo ra một hướng dẫn callvirt .

Xem bài đăng blog để biết chi tiết và một ví dụ:

Instance Methods Called on null References

mẫu

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  18 (0x12) 
    .maxstack 1 
    .locals init ([0] class SomeClass o, [1] string hello) 
    IL_0000: nop 
    IL_0001: ldnull 
    IL_0002: stloc.0 
    IL_0003: ldloc.0 
    IL_0004: call  instance string SomeClass::GetHello() 
    IL_0009: stloc.1 
    IL_000a: ldloc.1 
    IL_000b: call  void [mscorlib]System.Console::WriteLine(string) 
    IL_0010: nop 
    IL_0011: ret 
} 

Trong thực tế, lý do mà các biên dịch C# phát ra callvirt ngay cả trong trường hợp lệnh đơn giản call sẽ là đủ để ngăn chặn các phương thức thể hiện gọi trên tham chiếu null. Với hành vi này của người dùng trình biên dịch sẽ nhận được một NullReferenceException vì vậy tình huống kỳ lạ của việc gọi một phương thức trên một con trỏ null là tránh được. Eric Gunnerson đã giải thích điều này trong một bài đăng trên blog một thời gian trước đây: Why does C# always use callvirt?Gishu cũng có một lời giải thích thú vị trong một số related question.

5

Xem blog entry của tôi để biết thông tin.

IL code mẫu:

.class Program 
{ 
    .method static void Main(string[] args) 
    { 
    .entrypoint 
    .locals init ([0] class Program p) 
    ldloc.0 // but wait, it's still null! 
    call instance void Program::Awesome() 
    ret 
    } 

    .method instance void Awesome() 
    { 
    ldstr  "Awesome!" 
    call  void [mscorlib]System.Console::WriteLine(string) 
    ret 
    } 

    .method public specialname rtspecialname instance void .ctor() 
    { 
    ldarg.0 
    call  instance void [mscorlib]System.Object::.ctor() 
    ret 
    } 
} 
3

Các CLR không đòi hỏi nó, nó là một chi tiết thực hiện của ngôn ngữ. C# và VB.NET thực hiện kiểm tra. C++/CLI là một ngôn ngữ được quản lý đáng chú ý cho phép nó. Miễn là phương thức cá thể không tham chiếu bất kỳ thành viên lớp nào thì không có gì sai. Nếu có, NullReferenceException sẽ được nâng lên như bình thường, chỉ đơn thuần là cho bạn một thời gian khó khăn tìm ra lý do tại sao.

#include "stdafx.h" 

using namespace System; 

ref class Test { 
public: 
    void Run() { 
     Console::WriteLine("no problem"); 
    } 
}; 

int main(array<System::String ^> ^args) 
{ 
    Test^ obj = nullptr; 
    obj->Run(); 
    return 0; 
} 
Các vấn đề liên quan