2011-10-19 37 views
9

Có ai có thể giải thích cho tôi về hành vi kỳ lạ này không?Tại sao tôi nên bao quanh một cách rõ ràng với "không được chọn"?

int i = 0x1234; 
    byte b1 = (byte)i; 
    byte b2 = (byte)0x1234;   //error: const value '4660' can't convert to byte (use unchecked) 
    byte b3 = unchecked((byte)0x1234); 
    byte b4 = checked((byte)i);  //throws 
    byte b5 = (byte)(int)0x1234; //error: same as above 

Chú ý: Đây là một ứng dụng Console rỗng, với NO số học việc kiểm tra được kích hoạt (như mặc định là). Cảm ơn mọi người trước.

CHỈNH SỬA: Tôi phải đủ rõ ràng, nhưng không phải cho tất cả.

Tôi biết rằng một từ không thể vừa với một byte. Tuy nhiên, theo mặc định, một chương trình C# cho phép các hoạt động "nguy hiểm" nhất định, chủ yếu vì lý do hiệu suất.

Tương tự, tôi có thể tổng hợp hai số nguyên lớn với nhau và không có tràn nào cả.

Điều kỳ diệu của tôi là về lỗi biên dịch ở trên: phân đoạn/phép gán b1 được biên dịch, b2 không thể biên dịch được. Rõ ràng là không có sự khác biệt, bởi vì cả hai đều là Int32 có cùng giá trị.

Hy vọng điều đó đã rõ ràng.

+3

Tôi không nói C# và tôi không biết ý nghĩa "đã kiểm tra" và "không được chọn", nhưng tôi biết rằng bạn không thể vừa với số hex bốn chữ số trong một byte. –

+1

Hành vi nào là 'lạ' đối với bạn? Bạn đã cung cấp cho chúng tôi ** các bước để tạo lại ** và ** kết quả thực tế **, nhưng không ** kết quả mong đợi **. – AakashM

Trả lời

11

Bạn đang vấp ngã trên một phần của phần 7.19 của C# 4 spec:

Trừ khi một biểu thức hằng được đặt một cách rõ ràng trong bối cảnh unchecked, tràn xảy ra trong không thể thiếu loại phép tính số học và chuyển đổi trong việc đánh giá thời gian biên dịch của biểu thức luôn gây ra lỗi biên dịch.

Về cơ bản, vấn đề là ngay cả khi bạn đang hạnh phúc để cho phép hoạt động tràn tại thực hiện thời gian, nếu bạn đang cố gắng sử dụng một biểu thức hằng mà không thể được chuyển đổi sang các loại mục tiêu tại thời điểm biên dịch, bạn phải nói với trình biên dịch rằng bạn thực sự biết những gì bạn đang làm.

Ví dụ, trong trường hợp này bạn đang bị mất thông tin - nó sẽ tương đương với

byte b3 = 0x34; 

vì vậy bạn muốn thường được tốt hơn off chỉ cần xác định rằng, để cung cấp cho bạn mã rõ ràng hơn mà doesn không đánh lừa người đọc. Nó tương đối hiếm hoi mà bạn muốn tràn trong một hằng số - hầu hết thời gian bạn nên chỉ định giá trị hợp lệ thay thế.

+3

Bạn có vẻ như một luật sư trích dẫn _ "phần 7,19 của thông số C# 4" _. : D – Otiel

+0

Đối với tôi đó là tất cả các quyền, nhưng tại sao trình biên dịch không đưa vào tài khoản "Tràn số học" vô hiệu hóa là tốt? Cảm ơn bạn anyway: nó chỉ là một sự tò mò tôi va vào. –

+0

@MarioVernari: Bởi vì nó được thiết kế để thay đổi hành vi thời gian thực hiện - hầu hết mã C# có thể được xây dựng với mặc định đó, nhưng hầu hết các nhà phát triển vẫn nên quan tâm nếu các * hằng số * tràn của họ. –

1

Đây không phải là hành vi lạ, phạm vi hợp lệ cho một biến của loại dữ liệu byte0-255 nhưng khi bạn chuyển đổi giá trị HEX 0x1234 thành hệ thập phân bạn nhận được 4660. Vì vậy, unchecked được sử dụng để kiểm soát các phép tính số học và các phép chuyển đổi số học tích phân kiểm tra tràn.

Bạn có thể thấy rằng unchecked thường được sử dụng trong việc thực hiện GetHashCode() thực hiện các phép toán số để tính mã băm cuối cùng.

Để tóm tắt, bạn nên sử dụng unchecked khi giá trị kết quả cuối cùng của hoạt động loại số nguyên không quan trọng nhưng có thể xảy ra tràn.

1

Bạn không nên bao quanh điều này bằng cách bỏ chọn.Bỏ chọn cho phép gán các loại giá trị nguy hiểm cho một loại, điều này có thể gây tràn.

byte b1 = (byte)i; sẽ gây ra lỗi tràn hoặc truyền ngoại lệ khi chạy.

byte b2 = (byte)0x1234; không hợp lệ vì bạn không thể lưu trữ các giá trị lớn hơn 0xFF trong một byte.

byte b3 = unchecked((byte)0x1234); sẽ đặt 0x34 hoặc 0x12 (tùy thuộc vào việc triển khai CLR) vào b3 và byte khác sẽ tràn.

byte b4 = checked((byte)i); cũng giống như byte b1 = (byte)i;

byte b5 = (byte)(int)0x1234; sẽ đúc 0x1234 đến một int, và sau đó cố gắng đúc nó vào byte. Một lần nữa, bạn không thể chuyển đổi 0x1234 thành byte vì nó quá lớn.

+0

Vâng, bạn đã đúng một phần, nhưng không hề. Đúng là tránh kiểm tra là một thực tế nguy hiểm, nhưng bạn cũng nên sử dụng chúng với một chút bộ não, IMHO. KHÔNG PHẢI là sự thật, nhiệm vụ đầu tiên của bạn gây ra một ngoại lệ. Nó sẽ chỉ ném nếu bạn bật "kiểm tra số học" (mặc định là tắt). Bài tập thứ ba tôi đoán là sai: nó phải trả về luôn 0x12. Thứ tư: xem xét tương tự của đầu tiên. Thứ năm: giống như giây. Chúc mừng –

+0

Thứ ba sẽ luôn trả về 0x34, không phải 0x12. Và giá trị đầu tiên sẽ chỉ gây ra ngoại lệ nếu việc kiểm tra được bật VÀ nếu giá trị nằm ngoài phạm vi 0-255. – phoog

+0

Cảm ơn các bạn đã sửa lỗi :) – Polynomial

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