2009-02-23 36 views
11

Dường như với tôi rằng rất nhiều thời gian gỡ lỗi của tôi được dành để theo đuổi các ngoại lệ tham chiếu null trong các câu lệnh phức tạp. Ví dụ:Tại sao không thể đặt tên ngoại lệ tham chiếu null đối tượng có tham chiếu null?

For Each game As IHomeGame in _GamesToOpen.GetIterator() 

Tại sao, khi tôi nhận được NullReferenceException, tôi có thể lấy số dòng trong dấu vết ngăn xếp chứ không phải tên của đối tượng bằng null. Nói cách khác, tại sao:

Object reference not set to an instance of an object. 

thay vì

_GamesToOpen is not set to an instance of an object. 

hoặc

Anonymous object returned by _GamesToOpen.GetIterator() is null. 

hoặc

game was set to null. 

Đây có phải là hoàn toàn là một sự lựa chọn thiết kế, có nghĩa là để bảo vệ danh tính của mã hoặc có comp lý do elling trong thiết kế trình biên dịch không bao gồm thông tin này trong ngoại lệ thời gian gỡ lỗi?

Trả lời

11

Trường hợp ngoại lệ là những thứ thời gian chạy, các biến là thời gian biên dịch.

Thực tế, biến trong ví dụ của bạn là một biểu thức. Biểu thức không phải lúc nào cũng là các biến đơn giản. Khi chạy, biểu thức sẽ được đánh giá và phương thức sẽ được gọi trên đối tượng kết quả. Nếu giá trị của biểu thức đó là null, thời gian chạy sẽ ném một số NullReferenceException. Giả sử sau đây:

Dim a as New MyObject 
Dim b as String = MyObject.GetNullValue().ToString() 

nên sự trở lại thời gian chạy nếu phương pháp GetNullValue() trả về lỗi gì nhắn null?

+2

Số dòng cũng là một điều thời gian chạy. Trình biên dịch gỡ lỗi có chứa tất cả các loại thời gian biên dịch (tên lớp và phương thức, số dòng, v.v.) Tại sao không phải là tên biến? –

+1

Các lớp và phương pháp và tên tham số thực sự tồn tại ở cấp IL. Nhưng các biến được sử dụng khá nhiều trong IL được tạo ra. Về cơ bản, không có cách cụ thể nào để liên kết một ngoại lệ với một biến cụ thể: Giả sử "if (a

+0

Được chấp nhận vì nhận xét ở trên. –

1

Một cách đơn giản để nắm bắt điều này để gỡ lỗi để đặt câu lệnh khẳng định trước khi sử dụng một đối tượng, kiểm tra giá trị rỗng và xuất ra một thông báo có ý nghĩa.

+0

Nó không phải là allways có thể có một khẳng định. Ví dụ, bạn không thể thêm một khẳng định bên trong một biểu thức LINQ. –

+0

Sửa lỗi nếu tôi sai, nhưng tôi nghĩ các câu lệnh Assert được xóa khỏi các bản dựng được phát hành tối ưu. – Marc

1

Trong bản phát hành, tên biến sẽ bị loại khỏi biểu tượng và mã thậm chí có thể được tối ưu hóa để không có vị trí bộ nhớ cụ thể cho biến, nhưng chỉ giữ tham chiếu trong một trong các thanh ghi (tùy thuộc vào phạm vi của việc sử dụng biến). Do đó, có thể không thể khấu trừ tên của biến từ vị trí tham chiếu.

Trong bản dựng gỡ lỗi, có nhiều thông tin hơn về các biến. Tuy nhiên, đối tượng ngoại lệ cần phải làm việc theo cùng một cách không quan tâm đến hương vị xây dựng. Do đó, nó hoạt động dựa trên thông tin tối thiểu mà nó có thể truy cập trong bất kỳ hương vị nào.

+0

Tốt thôi. Bạn có thể không muốn nó trong bản phát hành xây dựng anyway. Tôi đã chỉ định trong câu hỏi mà tôi đã tự hỏi tại sao bạn không thể thấy điều này trong các bản dựng gỡ lỗi. –

+0

Tôi mặc dù tôi đã đề cập đến điều này. Các đối tượng ngoại lệ không phải là một tính năng gỡ lỗi và nên làm việc giống nhau bất kể hương vị xây dựng. Bạn sẽ không mong đợi hành vi của lớp String thay đổi triệt để dưới dạng Debug, đúng không? –

1

Một vài điều ...

1) khi bạn thực hiện ngoại lệ của riêng bạn ghi nhớ điều này (nếu bạn đang bực mình nó nó cho một người nào đó này khác sẽ cảm thấy khó chịu với bạn nếu bạn làm điều đó cho cái gì khác). Cho rằng con đường ngoại lệ không nên ở tất cả được con đường điển hình thời gian dành cho việc ngoại lệ có thông tin hữu ích cũng có giá trị nó.

2) như là một practive lập trình chung áp dụng phong cách này và bạn sẽ có những vấn đề ít (có mã của bạn sẽ còn về đường nét, nhưng bạn sẽ tiết kiệm được rất nhiều thời gian):

a) không bao giờ làm ab(). c(); do x = a.b(); x.c(); (trên các dòng riêng biệt) theo cách bạn có thể thấy một giá trị rỗng hoặc nếu trả về a.b() là null.

b) không bao giờ chuyển trả về cuộc gọi phương thức làm thông số - luôn chuyển các biến. a (foo()); nên là x = foo(); a (x); Điều này là nhiều hơn cho gỡ lỗi và có thể nhìn thấy giá trị.

Tôi không biết tại sao các môi trường như .net và Java không cung cấp phiên bản thời gian chạy có nhiều thông tin hơn về các loại ngoại lệ này, chẳng hạn như chỉ mục nằm trên một mảng ngoài giới hạn, tên của biến khi nó là null, vv ...

2

đối với các ngôn ngữ như Java được biên dịch để bytecode đó được giải thích bởi một máy ảo, giả sử bạn có một lớp X với một lĩnh vực x, và giá trị của nó là null cho một tham chiếu nhất định. Nếu bạn viết

x.foo() 

bytecode có thể trông như thế này:

push Xref   >> top of stack is ref to instance of X with X.x = null 
getField x   >> pops Xref, pushes 'null' on the stack 
invokeMethod foo >> pops 'null' -> runtime exception 

Vấn đề là các hoạt động mà cần một tham chiếu null trên stack để hoạt động trên nó, như invokeMethod trong ví dụ , không thể và không biết tham chiếu null đến từ đâu.

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