2014-09-25 14 views
11

Tôi đã mượn mã dưới đây từ another question (chút thay đổi), để sử dụng trong mã của tôi:Tại sao/khi nào điều quan trọng là phải chỉ định toán tử là rõ ràng?

internal class PositiveDouble 
{ 
     private double _value; 
     public PositiveDouble(double val) 
     { 
      if (val < 0) 
       throw new ArgumentOutOfRangeException("Value needs to be positive"); 
      _value = val; 
     } 

     // This conversion is safe, we can make it implicit 
     public static implicit operator double(PositiveDouble d) 
     { 
      return d._value; 
     } 
     // This conversion is not always safe, so we're supposed to make it explicit 
     public static explicit operator PositiveDouble(double d) 
     { 
      return new PositiveDouble(d); // this constructor might throw exception 
     } 
} 

Tác giả ban đầu của mã này tuân thủ một cách chính xác để những lời cảnh báo được đưa ra trong tài liệu hướng dẫn implicit & explicit MSDN, nhưng đây là Câu hỏi của tôi: Có phải explicit luôn cần thiết trong mã có khả năng đặc biệt?

Vì vậy, tôi đã có một số loại trong mã của tôi (ví dụ: "Khối lượng") có nguồn gốc từ PositiveDouble và tôi muốn để có thể thiết lập các trường hợp thuận tiện như dòng đầu tiên dưới đây:

Volume v = 10; //only allowed by implicit conversion 
Volume v = new Volume(10) //required by explicit conversion, but gets messy quick 

Buộc phải sử dụng các phôi rõ ràng ở khắp mọi nơi làm cho mã ít dễ đọc hơn. Nó bảo vệ người dùng như thế nào? Trong ngữ nghĩa của chương trình của tôi, tôi không bao giờ mong đợi một Khối lượng âm; thực sự, nếu nó bao giờ xảy ra tôi mong đợi một ngoại lệ được ném. Vì vậy, nếu tôi sử dụng một chuyển đổi tiềm ẩn và nó ném, những gì "kết quả bất ngờ" có thể clobber tôi?

+0

Dường như tôi thay đổi toán tử chuyển đổi của bạn thành ngầm nên ở đây. – Botonomous

+1

Được khuyến nghị, đặc biệt trong API công khai. Nó ngăn cản mọi người sử dụng diễn viên mà không nhận thấy nó có thể ném, tiết kiệm thời gian trong việc gỡ lỗi. Làm cho mọi người chú ý đến diễn viên sẽ tránh rắc rối. Họ nói "oh, vì vậy bạn nghĩ rằng bạn đang thông minh làm cho tất cả các diễn viên tiềm ẩn?" và bạn nói "Nếu bạn biết bạn đang làm gì, bạn sẽ không gặp vấn đề gì" - hãy tưởng tượng một cái bếp bắt đầu khi có thứ gì đó trên đó, bởi vì "Bị buộc phải khởi động bếp mỗi lần nấu ít hiệu quả hơn", và các nhà sản xuất đáp ứng với tuyên bố với "sau đó không đặt mọi thứ vào nó" - chỉ ít kịch tính và không có bỏng. – Theraot

Trả lời

14

C đặc điểm kỹ thuật # ngôn ngữ nói dưới 10.10.3 nhà khai thác chuyển đổi:

Nếu chuyển đổi người dùng định nghĩa có thể làm phát sinh trường hợp ngoại lệ (ví dụ, bởi vì đối số nguồn là ra khỏi phạm vi) hoặc mất thông tin (chẳng hạn như loại bỏ các bit có thứ tự cao), thì chuyển đổi đó nên được định nghĩa là một chuyển đổi rõ ràng.

Ngoài ra, từ MSDN: implicit (C# Reference):

Nói chung, các nhà khai thác chuyển đổi ngầm không bao giờ nên ném ngoại lệ và không bao giờ mất thông tin để họ có thể được sử dụng một cách an toàn mà không cần nhận thức của lập trình viên. Nếu nhà điều hành chuyển đổi không thể đáp ứng các tiêu chí đó, thì phải được đánh dấu là khiêu dâm.

Xét này, bạn operator PositiveDouble(double d)nên không được đánh dấu implicit, như Volume v = -1 sẽ ném một ngoại lệ.

Vì vậy, để trả lời câu hỏi của bạn:

là rõ ràng luôn luôn cần thiết trong mã có khả năng đặc biệt?

Không, không cần thiết, nhưng nên.

Dựa vào dựa trên ý kiến: nếu mã của bạn là mã duy nhất sử dụng chuyển đổi này và bạn thấy chuyển đổi ngầm định dễ đọc và/hoặc duy trì, vui lòng sử dụng điều đó.

Đối với

như thế nào bảo vệ người sử dụng?

Xem MSDN: explicit (C# Reference) đề cập:

Nếu một thao tác chuyển đổi có thể gây ra ngoại lệ hoặc mất thông tin, bạn nên đánh dấu nó rõ ràng. Điều này ngăn cản trình biên dịch từ âm thầm gọi hoạt động chuyển đổi với các hậu quả có thể không lường trước được.

Tôi thực sự không thể hiểu được khi điều này xảy ra, nhưng một lần nữa, nếu bạn nghĩ bạn không bao giờ chuyển đổi từ âm kép trong mã của bạn ở bất kỳ đâu, điều này không bao giờ nên ném.

+2

* "Tôi không thể thực sự hiểu được khi điều này xảy ra" * - Nó có thể dễ dàng xảy ra khi truyền các đối tượng với các chuyển đổi tùy chỉnh đến các phương thức khung mà chấp nhận các đối số đó. Nó không thực sự rõ ràng trong mã rằng điều này sẽ xảy ra trừ khi bạn (a) biết chính xác loại đối số (s) phương pháp khung chấp nhận, và (b) biết rằng chuyển đổi tiềm ẩn tồn tại. – cdhowie

13

Chuyển đổi chỉ nên ẩn nếu chúng luôn thành công. Nếu họ có thể thất bại hoặc gây mất thông tin, họ phải rõ ràng, bởi vì điều này đòi hỏi người gọi của hoạt động chuyển đổi cố tình chỉ ra rằng họ muốn chuyển đổi này và do đó được chuẩn bị để đối phó với kết quả, bất kể điều gì có thể xảy ra.

Chúng ta có thể thấy điều này trong các loại số nguyên thủy của khung công tác; chỉ định một int cho một long là một chuyển đổi tiềm ẩn, bởi vì nó sẽ luôn thành công với kết quả mong muốn. Đi theo một cách khác có thể gây ra một OverflowException trong ngữ cảnh được chọn và có thể gây cắt ngắn (mất thông tin) trong ngữ cảnh không được kiểm soát, vì vậy bạn được yêu cầu cho biết rằng bạn dự định chuyển đổi này bằng cách truyền một cách rõ ràng.

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