Tôi có nên sử dụng uint trong C # cho các giá trị không thể âm không?


79

Tôi vừa cố gắng thực hiện một lớp học nơi nhiều thuộc tính chiều dài / đếm, vv là uintthay vì int. Tuy nhiên, trong khi làm như vậy, tôi nhận thấy rằng thực sự rất đau khi làm như vậy, như thể không ai thực sự muốn làm điều đó.

Gần như mọi thứ đưa ra kiểu tích phân đều trả về một int, do đó yêu cầu phôi ở một số điểm. Tôi muốn xây dựng một StringBuffervới độ dài bộ đệm của nó được mặc định cho một trong các trường trong lớp đó. Yêu cầu một dàn diễn viên quá.

Vì vậy, tôi tự hỏi liệu tôi có nên quay lại intđây không. Tôi chắc chắn không sử dụng toàn bộ phạm vi dù sao. Tôi chỉ nghĩ vì những gì tôi đang giải quyết ở đó đơn giản không thể là tiêu cực (nếu có, nó sẽ là một lỗi) nên thực sự là một ý tưởng hay uint.

Tái bút: Tôi đã thấy câu hỏi này và điều này ít nhất giải thích tại sao bản thân khung công tác luôn sử dụng intnhưng ngay cả trong mã riêng, nó thực sự cồng kềnh để dính vào uintkhiến tôi nghĩ rằng nó dường như không thực sự muốn.


Câu trả lời:


42

Mặc dù nghiêm ngặt bạn nên sử dụng uintcho các biến chứa số nguyên không âm, bạn đã gặp một trong những lý do tại sao nó không phải lúc nào cũng khả thi.

Trong trường hợp này, tôi không nghĩ rằng việc giảm khả năng đọc đi kèm với việc phải phân vai là đáng giá.


2
Thật khó để nói, tôi không nghĩ rằng các phôi làm giảm tính dễ đọc rất nhiều cho chỉ những người lập chỉ mục và bạn có thể tạo một trình bao bọc. Và các int trở nên tiêu cực là lỗi đau đớn và tốn kém.
dùng1496062

6
Nếu bạn phải tạo một wrapper cho một int thì bạn gặp nhiều vấn đề hơn là khả năng đọc :)
S ..

61

Tôi cũng sẽ thêm vào các câu trả lời khác rằng việc sử dụng uint làm kiểu trường công khai, thuộc tính, phương thức, tham số, v.v., là vi phạm các quy tắc Đặc tả ngôn ngữ chung và cần tránh khi có thể.


3
Và tôi đã bị Microsoft đốt cháy theo đúng điều đó. Nó chỉ ra rằng IntPtr nên có một phương thức khởi tạo uint.
Joshua

3
Tôi cũng sẽ nói thêm nếu họ hỗ trợ số tự nhiên, ví dụ loại này là giá trị từ 0 đến 6, họ có thể loại bỏ tất cả việc kiểm tra giới hạn mảng, tăng hiệu suất lên 5-10%.
user1496062

Ông có đồng tình với nhận định trên không, ông Lippert?
AgentFire

@AgentFire: Tuyên bố khẳng định rằng nếu ai đó đã làm điều gì đó, điều đó sẽ dẫn đến cải thiện hiệu suất cụ thể. Tôi không có khả năng đánh giá các tuyên bố phản thực tế; nếu bạn muốn biết liệu tuyên bố đó có đúng không, hãy hỏi người dùng1496062 điều gì biện minh cho tuyên bố của họ, không phải tôi; Tôi không phải là người đưa ra yêu cầu không được hỗ trợ.
Eric Lippert

1
@EricLippert, đó là một trong những câu "tôi không biết" dài nhất của bạn, phải không: p
AgentFire

4

Giá trị âm thường được sử dụng để báo hiệu một điều kiện lỗi và kích thước của một hoạt động thường được trả về bởi một lệnh gọi hàm; do đó giá trị âm có thể báo hiệu lỗi mà không cần dùng đến cơ chế ngoại lệ.

Cũng lưu ý rằng .NET thường xây dựng dựa trên các thư viện C thẳng, do đó, việc tiếp tục quy ước này là hợp lý. Nếu bạn yêu cầu không gian chỉ mục lớn hơn, bạn có thể phá vỡ quy ước cho cơ chế báo hiệu lỗi khác nhau.


24
.NET khá nhất quán với việc ném ra các ngoại lệ thay vì trả về mã lỗi. Lợi nhuận -1 không phải là điều phổ biến trong mã được quản lý.
ChrisV

đã đồng ý, nhưng chúng ta đang nói về một quy ước thiết kế phổ biến trong các công nghệ windows (ngoài các trường hợp ngoại lệ được hỗ trợ) - những phần của thư viện .NET giao diện với mã cấp thấp phải dịch giữa mã lỗi CRT và ngoại lệ - có thể hiểu được tại sao họ đưa ra quy ước của int hơn là uint.
Hassan Syed

@HassanSyed vẫn còn, nếu một số winapi trả về giá trị âm, thì khung công tác sẽ vẫn ném ngoại lệ của riêng nó, gói mọi thứ vào một trình bao gọn gàng, vì vậy đối số đó không cố ý áp dụng ở đây.
AgentFire

3

Cảm giác cá nhân của tôi là bạn có lẽ chỉ nên dính vào int. Thật không đáng để thêm một cast vào hầu hết mọi quyền truy cập thuộc tính chỉ để lấy lại một dải số mà .NET không có khả năng cho phép bạn sử dụng.


3

Sử dụng int cũng hữu ích để phát hiện tràn số nguyên trong các phép toán.


Không chính xác 100%, nếu nó tràn đến mức không. Một lần nữa, có một bảo vệ chống tràn được bật theo mặc định.
AgentFire

3

IMO, hạn chế của việc sử dụng uintlà nó che khuất các điều kiện lỗi. Các đoạn mã tương đương sau đây không đẹp bằng:

if (len < 0)
    terminate_program("length attained impossible value.");

Tất nhiên các chương trình của bạn không nên tính toán sai bất cứ thứ gì để bắt đầu, nhưng tôi cảm thấy chúng cũng nên được viết để nhanh chóng phát hiện các lỗi số mà không cần truyền bá. Trong trường hợp MaxValue là 2 ^ 31 là đủ, tôi nói hãy sử dụng intcùng với việc sử dụng thích hợp System.Diagnostics.Debug.Assert()và kiểm tra lỗi tương ứng như được ví dụ ở trên.

Nếu bạn sử dụng, hãy sử uintdụng nó cùng với checkedđể ngăn chặn dòng chảy dưới và nhận được kết quả tương tự. Tuy nhiên, tôi nhận thấy rằng việc kiểm tra hơi khó áp dụng cho mã hiện có sử dụng phôi cho một số mục đích.


2

Đừng bơi ngược dòng nếu bạn không cần thiết. Việc không làm sáng tỏ mã của bạn với phôi làm cho mã của bạn dễ đọc hơn. Hơn nữa, nếu các giá trị có thể có của bạn phù hợp với một số nguyên, thì việc sử dụng một số nguyên không phải là một vấn đề.

Nếu bạn sợ rằng mình có thể làm tràn một int, thì hãy có bằng mọi cách .. nhưng đừng tối ưu hóa quá sớm.

Tôi có thể nói rằng khả năng đọc được cải thiện của việc giảm thiểu phôi vượt quá nguy cơ lỗi cao hơn một chút khi sử dụng int.


2

Nếu bạn muốn kiểm tra xem một giá trị có dương hay không, thì cách tốt hơn có thể là sử dụng khẳng định (lưu ý rằng đây chỉ là một kỹ thuật gỡ lỗi - bạn nên đảm bảo rằng điều này không bao giờ xảy ra trong mã cuối cùng).

using System.Diagnostics;
...
Debug.Assert (i > 0);

1
Xem thêm ArgumentOutOfRangeException.
Fred
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.