Đánh giá ngắn mạch, nó là thực hành xấu?


88

Một điều mà tôi đã biết trong một thời gian nhưng chưa bao giờ cân nhắc là trong hầu hết các ngôn ngữ, có thể ưu tiên cho các nhà khai thác trong một câu lệnh if dựa trên thứ tự của họ. Tôi thường sử dụng điều này như một cách để ngăn chặn các ngoại lệ tham chiếu null, ví dụ:

if (smartphone != null && smartphone.GetSignal() > 50)
{
   // Do stuff
}

Trong trường hợp này, mã sẽ dẫn đến việc kiểm tra đầu tiên rằng đối tượng không phải là null và sau đó sử dụng đối tượng này biết rằng nó tồn tại. Ngôn ngữ là thông minh bởi vì nó biết rằng nếu câu lệnh đầu tiên nếu sai thì sẽ không có điểm nào đánh giá câu lệnh thứ hai và do đó, một ngoại lệ tham chiếu null không bao giờ được đưa ra. Điều này hoạt động tương tự cho andvà các ornhà khai thác.

Điều này cũng có thể hữu ích trong các tình huống khác như kiểm tra xem một chỉ mục nằm trong giới hạn của một mảng và một kỹ thuật như vậy có thể được thực hiện bằng nhiều ngôn ngữ khác nhau, theo hiểu biết của tôi: Java, C #, C ++, Python và Matlab.

Câu hỏi của tôi là: Đây có phải là loại mã đại diện cho thực tiễn xấu? Liệu thực tiễn xấu này phát sinh từ một số vấn đề kỹ thuật ẩn (nghĩa là điều này cuối cùng có thể dẫn đến một lỗi) hoặc nó dẫn đến một vấn đề dễ đọc cho các lập trình viên khác? Nó có thể gây nhầm lẫn?


69
Thuật ngữ kỹ thuật là đánh giá ngắn mạch . Đây là một kỹ thuật thực hiện nổi tiếng và nơi mà tiêu chuẩn ngôn ngữ đảm bảo cho nó, dựa vào nó là một điều tốt. (Nếu không, đó không phải là ngôn ngữ, IMO.)
Kilian Foth

3
Hầu hết các ngôn ngữ cho phép bạn chọn những hành vi bạn muốn. Trong C #, toán tử ||ngắn mạch, toán tử |(ống đơn) không ( &&&hoạt động giống nhau). Vì các toán tử ngắn mạch được sử dụng thường xuyên hơn nhiều, tôi khuyên bạn nên đánh dấu việc sử dụng các toán tử không ngắn mạch bằng một nhận xét để giải thích lý do tại sao bạn cần hành vi của chúng (chủ yếu là những điều như các yêu cầu phương pháp mà tất cả cần phải xảy ra).
linac

14
@linac hiện đang đặt thứ gì đó ở phía bên phải &hoặc |để đảm bảo tác dụng phụ xảy ra là điều tôi chắc chắn là thực hành tồi: Sẽ không tốn kém gì khi bạn gọi phương thức đó theo cách riêng của mình.
Jon Hanna

14
@linac: Trong C và C ++, &&ngắn mạch và &không, nhưng chúng là các toán tử rất khác nhau. &&là một logic "và"; &là một chút "và". Điều đó có x && ythể đúng trong khi đó x & ylà sai.
Keith Thompson

3
Ví dụ cụ thể của bạn có thể là thực tiễn xấu vì một lý do khác: nếu nó null thì sao? Có hợp lý cho nó là null ở đây? Tại sao nó là null? Phần còn lại của chức năng bên ngoài khối này sẽ thực thi nếu nó là null, toàn bộ điều này có nên làm gì không, hay chương trình của bạn nên dừng lại? Tăng cường "nếu không" trên mọi truy cập (có thể do ngoại lệ tham chiếu null mà bạn đang vội vã loại bỏ) có nghĩa là bạn có thể đi sâu vào phần còn lại của chương trình, mà không bao giờ nhận thấy rằng việc khởi tạo đối tượng điện thoại bị vặn lên. Và cuối cùng, khi bạn cuối cùng đã có được một chút mã mà không không
Random832

Câu trả lời:


125

Không, đây không phải là thực hành xấu. Dựa vào ngắn mạch các điều kiện là một kỹ thuật hữu ích, được chấp nhận rộng rãi - miễn là bạn đang sử dụng một ngôn ngữ đảm bảo hành vi này (bao gồm phần lớn các ngôn ngữ hiện đại).

Ví dụ mã của bạn khá rõ ràng và thực sự, đó thường là cách tốt nhất để viết nó. Các lựa chọn thay thế (như các ifcâu lệnh lồng nhau ) sẽ lộn xộn hơn, phức tạp hơn và do đó khó hiểu hơn.

Một vài cảnh báo:

Sử dụng thông thường liên quan đến sự phức tạp và dễ đọc

Sau đây không phải là một ý tưởng tốt:

if ((text_string != null && replace(text_string,"$")) || (text_string = get_new_string()) != null)

Giống như nhiều cách "thông minh" để giảm các dòng trong mã của bạn, việc phụ thuộc quá nhiều vào kỹ thuật này có thể dẫn đến mã khó hiểu, dễ bị lỗi.

Nếu bạn cần xử lý lỗi, thường có cách tốt hơn

Ví dụ của bạn là tốt miễn là nó là một trạng thái chương trình bình thường cho điện thoại thông minh là null. Tuy nhiên, nếu đây là một lỗi, bạn nên kết hợp xử lý lỗi thông minh hơn.

Tránh kiểm tra lặp lại cùng một điều kiện

Như Neil chỉ ra, nhiều kiểm tra lặp lại của cùng một biến trong các điều kiện khác nhau rất có thể là bằng chứng của một lỗ hổng thiết kế. Nếu bạn có mười câu lệnh khác nhau được rắc qua mã của bạn không nên chạy nếu smartphonenull, hãy xem xét liệu có cách nào tốt hơn để xử lý việc này hơn là kiểm tra biến mỗi lần.

Đây không thực sự là về ngắn mạch cụ thể; đó là một vấn đề chung hơn của mã lặp đi lặp lại. Tuy nhiên, điều đáng nói, bởi vì khá phổ biến khi thấy mã có nhiều câu lệnh lặp lại như câu lệnh ví dụ của bạn.


12
Cần lưu ý rằng lặp đi lặp lại nếu các khối kiểm tra nếu một thể hiện là null trong đánh giá ngắn mạch có lẽ nên được viết lại để thực hiện kiểm tra đó một lần.
Neil

1
@Neil, điểm tốt; Tôi cập nhật câu trả lời.

2
Điều duy nhất tôi có thể nghĩ thêm là lưu ý một cách xử lý tùy chọn khác, nó thực sự được ưa thích nếu bạn sẽ kiểm tra một cái gì đó trong nhiều điều kiện khác nhau: kiểm tra xem liệu có gì đó không trong if () không, sau đó trở lại / ném - nếu không chỉ cần tiếp tục đi. Điều này giúp loại bỏ việc lồng nhau và thường có thể làm cho mã rõ ràng và ngắn gọn hơn, vì trong "điều này không nên là null và nếu đó là tôi ra khỏi đây" - được đặt càng sớm càng tốt trong mã. Tuyệt vời bất cứ lúc nào bạn mã hóa một cái gì đó kiểm tra một điều kiện cụ thể nhiều hơn ở một nơi trong một phương thức.
BrianH

1
@ dan1111 Tôi sẽ khái quát ví dụ bạn đã đưa ra là "Một điều kiện không nên có tác dụng phụ (chẳng hạn như gán biến ở trên). Đánh giá ngắn mạch không thay đổi điều này và không nên được sử dụng làm tay ngắn cho một bên- hiệu ứng có thể dễ dàng được đặt trong cơ thể của if để thể hiện tốt hơn mối quan hệ if / then. "
AaronLS

@AaronLS, tôi hoàn toàn không đồng ý với tuyên bố rằng "một điều kiện không nên có tác dụng phụ". Một điều kiện không nên gây nhầm lẫn một cách không cần thiết, nhưng miễn là nó rõ ràng, tôi ổn với một tác dụng phụ (hoặc thậm chí nhiều hơn một tác dụng phụ) trong một điều kiện.

26

Giả sử bạn đang sử dụng ngôn ngữ kiểu C không có &&và cần thiết để thực hiện mã tương đương như trong câu hỏi của bạn.

Mã của bạn sẽ là:

if(smartphone != null)
{
  if(smartphone.GetSignal() > 50)
  {
    // Do stuff
  }
}

Mô hình này sẽ bật lên rất nhiều.

Bây giờ hãy tưởng tượng phiên bản 2.0 của ngôn ngữ giả định của chúng tôi giới thiệu &&. Hãy nghĩ rằng bạn nghĩ nó tuyệt như thế nào!

&&là phương tiện thành ngữ được công nhận để làm những gì ví dụ của tôi ở trên. Sử dụng nó không phải là thực hành xấu, thực sự đó là thực tế tồi khi không sử dụng nó trong các trường hợp như trên: Một lập trình viên có kinh nghiệm trong ngôn ngữ như vậy sẽ tự hỏi đâu elselà lý do hay lý do khác để không làm mọi thứ theo cách thông thường.

Ngôn ngữ là thông minh bởi vì nó biết rằng nếu câu lệnh đầu tiên nếu sai thì sẽ không có điểm nào đánh giá câu lệnh thứ hai và vì vậy một ngoại lệ tham chiếu null không bao giờ được đưa ra.

Không, bạn thông minh, bởi vì bạn biết rằng nếu tuyên bố đầu tiên là sai thì thậm chí không có điểm nào để đánh giá tuyên bố thứ hai. Ngôn ngữ câm như một hộp đá và làm những gì bạn bảo nó làm. (John McCarthy thậm chí còn thông minh hơn, và nhận ra rằng đánh giá ngắn mạch sẽ là một điều hữu ích cho các ngôn ngữ cần có).

Sự khác biệt giữa bạn thông minh và ngôn ngữ thông minh là rất quan trọng, bởi vì thực hành tốt và xấu thường khiến bạn trở nên thông minh khi cần thiết, nhưng không thông minh hơn.

Xem xét:

if(smartphone != null && smartphone.GetSignal() > ((range = (range != null ? range : GetRange()) != null && range.Valid ? range.MinSignal : 50)

Điều này mở rộng mã của bạn để kiểm tra a range. Nếu rangelà null thì nó cố gắng đặt nó bằng một cuộc gọi GetRange()mặc dù điều đó có thể thất bại nên rangevẫn có thể là null. Nếu phạm vi không phải là null sau đó, và đó là thuộc Validtính của nó MinSignalđược sử dụng, nếu không thì mặc định 50được sử dụng.

Điều này cũng phụ thuộc vào &&nó, nhưng đặt nó vào một dòng có lẽ quá thông minh (tôi không chắc chắn 100% mình có đúng không và tôi sẽ không kiểm tra lại vì thực tế đó chứng minh quan điểm của tôi).

&&Mặc dù đây không phải là vấn đề ở đây, nhưng khả năng sử dụng nó để đặt nhiều vào một biểu thức (một điều tốt) làm tăng khả năng viết các biểu thức khó hiểu một cách không cần thiết (một điều xấu).

Cũng thế:

if(smartphone != null && (smartphone.GetSignal() == 2 || smartphone.GetSignal() == 5 || smartphone.GetSignal() == 8 || smartPhone.GetSignal() == 34))
{
  // do something
}

Ở đây tôi đang kết hợp việc sử dụng &&với kiểm tra các giá trị nhất định. Điều này không thực tế trong trường hợp tín hiệu điện thoại, nhưng không xuất hiện trong các trường hợp khác. Đây là một ví dụ về việc tôi không đủ thông minh. Nếu tôi đã làm như sau:

if(smartphone != null)
{
  switch (smartphone.GetSignal())
  {
    case 2: case 5: case 8: case 34:
      // Do something
      break;
  }
}

Tôi đã đạt được cả về khả năng đọc và cả khả năng thực hiện (nhiều cuộc gọi đến GetSignal()có thể sẽ không được tối ưu hóa).

Một lần nữa, vấn đề không phải &&là lấy cái búa đặc biệt đó và xem mọi thứ khác như cái đinh; không sử dụng nó cho phép tôi làm một cái gì đó tốt hơn so với sử dụng nó.

Một trường hợp cuối cùng tránh xa thực tiễn tốt nhất là:

if(a && b)
{
  //do something
}

So với:

if(a & b)
{
  //do something
}

Lập luận cổ điển về lý do tại sao chúng ta có thể ủng hộ cái sau là có một số tác dụng phụ trong việc đánh giá brằng chúng ta muốn liệu acó đúng hay không. Tôi không đồng ý rằng: Nếu tác dụng phụ đó rất quan trọng, thì hãy làm cho nó xảy ra trong một dòng mã riêng biệt.

Tuy nhiên, về mặt hiệu quả, một trong hai có khả năng tốt hơn. Đầu tiên rõ ràng sẽ thực thi ít mã hơn (hoàn toàn không đánh giá btrong một đường dẫn mã) có thể giúp chúng tôi tiết kiệm bất kỳ khoảng thời gian nào để đánh giá b.

Đầu tiên mặc dù cũng có thêm một chi nhánh. Hãy xem xét nếu chúng ta viết lại nó bằng ngôn ngữ kiểu C giả định mà không có &&:

if(a)
{
  if(b)
  {
    // Do something
  }
}

Phần bổ sung đó ifđược ẩn trong việc sử dụng của chúng tôi &&, nhưng nó vẫn còn đó. Và như vậy, đó là một trường hợp có dự đoán chi nhánh xảy ra và do đó có khả năng dự đoán sai chi nhánh.

Vì lý do đó, if(a & b)mã có thể hiệu quả hơn trong một số trường hợp.

Ở đây tôi muốn nói rằng đó if(a && b)vẫn là cách tiếp cận thực tiễn tốt nhất để bắt đầu: Phổ biến hơn, duy nhất khả thi trong một số trường hợp (trong đó bsẽ có lỗi nếu alà sai) và nhanh hơn thường xuyên hơn không. Tuy nhiên, điều đáng chú ý if(a & b)là thường tối ưu hóa hữu ích trong một số trường hợp.


1
Nếu một người có tryphương pháp trở lại truetrong trường hợp thành công, bạn nghĩ if (TryThis || TryThat) { success } else { failure }gì? Đó là một thành ngữ ít dấu phẩy, nhưng tôi không biết làm thế nào để hoàn thành điều tương tự mà không cần sao chép mã hoặc thêm cờ. Mặc dù bộ nhớ cần thiết cho một cờ sẽ không phải là vấn đề, nhưng từ quan điểm phân tích, việc thêm một cờ có hiệu quả phân tách mã thành hai vũ trụ song song - một chứa các câu lệnh có thể tiếp cận được khi cờ truevà một câu lệnh khác có thể tiếp cận được khi nó false. Đôi khi tốt từ quan điểm DRY, nhưng icky.
supercat

5
Tôi thấy không có gì sai với if(TryThis || TryThat).
Jon Hanna

3
Chết tiệt trả lời tốt, thưa ông.
giám mục

FWIW, các lập trình viên xuất sắc bao gồm Kernighan, Plauger & Pike từ Bell Labs khuyên bạn nên sử dụng các cấu trúc điều khiển nông như if {} else if {} else if {} else {}thay vì các cấu trúc điều khiển lồng nhau như thế if { if {} else {} } else {}, ngay cả khi điều đó có nghĩa là đánh giá cùng một biểu thức nhiều lần. Linus Torvalds đã nói một điều tương tự: "nếu bạn cần nhiều hơn 3 cấp độ thụt, dù sao bạn cũng bị lừa". Hãy coi đó là một cuộc bỏ phiếu cho các nhà khai thác ngắn mạch.
Sam Watkins

câu lệnh if (a && b); là hợp lý dễ dàng để thay thế. if (a && b && c && d) statement1; câu lệnh khác2; là một nỗi đau thực sự.
gnasher729

10

Bạn có thể thực hiện điều này hơn nữa, và trong một số ngôn ngữ, đó là cách thành ngữ để thực hiện: bạn cũng có thể sử dụng tính ngắn gọn bên ngoài các câu điều kiện và chúng trở thành một dạng của câu lệnh có điều kiện. Ví dụ, trong Perl, thành ngữ cho các hàm trả lại một cái gì đó sai lầm khi thất bại (và một cái gì đó trung thực về thành công), và một cái gì đó như

open($handle, "<", "filename.txt") or die "Couldn't open file!";

là thành ngữ. opentrả lại một cái gì đó không thành công khi thành công (để diephần sau orkhông bao giờ xảy ra), nhưng không xác định được về thất bại, và sau đó cuộc gọi diesẽ xảy ra (đó là cách của Perl để đưa ra một ngoại lệ).

Điều đó là tốt trong ngôn ngữ mà mọi người làm điều đó.


17
Đóng góp lớn nhất của Perl cho thiết kế ngôn ngữ là cung cấp nhiều ví dụ về cách không làm điều đó.
Jack Aidley

@JackAidley: Mặc dù vậy, tôi nhớ Perl's unlessvà postfix điều kiện ( send_mail($address) if defined $address).
RemcoGerlich

6
@JackAidley bạn có thể cung cấp một con trỏ về lý do tại sao 'hoặc chết' là xấu? Có phải chỉ là một cách xử lý ngoại lệ ngây thơ?
bigstones

Có thể làm rất nhiều điều khủng khiếp trong Perl, nhưng tôi không thấy vấn đề với ví dụ này. Nó đơn giản, ngắn gọn và rõ ràng - chính xác những gì bạn muốn từ việc xử lý lỗi trong ngôn ngữ kịch bản.

1
@RemcoGerlich Ruby được thừa hưởng một số phong cách đó:send_mail(address) if address
bonh

6

Mặc dù tôi thường đồng ý với câu trả lời của dan1111 , có một trường hợp đặc biệt quan trọng không bao gồm: trường hợp smartphoneđược sử dụng đồng thời. Trong kịch bản đó, loại mô hình này là một nguồn nổi tiếng của các lỗi khó tìm.

Vấn đề là đánh giá ngắn mạch không phải là nguyên tử. Chủ đề của bạn có thể kiểm tra đó smartphonenull, một chủ đề khác có thể đi vào và vô hiệu hóa nó, và sau đó chủ đề của bạn nhanh chóng cố gắng GetSignal()và nổ tung.

Nhưng tất nhiên, nó chỉ thực hiện khi các ngôi sao sắp xếp thời gian và chủ đề của bạn là chỉ đúng.

Vì vậy, trong khi loại mã này rất phổ biến và hữu ích, điều quan trọng là phải biết về cảnh báo này để bạn có thể ngăn chặn chính xác lỗi khó chịu này.


3

Có rất nhiều tình huống tôi muốn kiểm tra một điều kiện trước, và chỉ muốn kiểm tra điều kiện thứ hai nếu điều kiện thứ nhất thành công. Đôi khi hoàn toàn là vì hiệu quả (vì không có điểm nào kiểm tra điều kiện thứ hai nếu điều thứ nhất đã thất bại), đôi khi vì nếu không chương trình của tôi sẽ bị sập (kiểm tra NULL trước), đôi khi vì nếu không thì kết quả sẽ rất tệ. (NẾU (Tôi muốn in tài liệu) VÀ (in tài liệu không thành công)) THÌ hiển thị thông báo lỗi - bạn không muốn in tài liệu và kiểm tra xem việc in có thất bại hay không nếu bạn không muốn in tài liệu trong địa điểm đầu tiên!

Vì vậy, có một nhu cầu rất lớn để đánh giá ngắn mạch được đảm bảo các biểu thức logic. Nó không có mặt trong Pascal (có đánh giá ngắn mạch không được bảo đảm) là một nỗi đau lớn; Tôi đã nhìn thấy nó lần đầu tiên trong Ada và C.

Nếu bạn thực sự nghĩ rằng đây là "thực hành xấu", thì vui lòng lấy bất kỳ đoạn mã phức tạp vừa phải nào, viết lại để nó hoạt động tốt mà không cần đánh giá ngắn mạch, và quay lại và cho chúng tôi biết bạn thích nó như thế nào. Điều này giống như được nói rằng thở tạo ra carbon dioxide và hỏi nếu thở là một thực hành xấu. Hãy thử mà không có nó trong vài phút.


"Viết lại nó để nó hoạt động tốt mà không cần đánh giá ngắn mạch, và quay lại và cho chúng tôi biết bạn thích nó như thế nào." - Vâng, điều này mang lại những ký ức về Pascal. Và không, tôi không thích nó.
Thomas Padron-McCarthy

2

Một sự xem xét, không được đề cập trong các câu trả lời khác: đôi khi có những kiểm tra này có thể gợi ý về khả năng tái cấu trúc có thể cho mẫu thiết kế Null Object . Ví dụ:

if (currentUser && currentUser.isAdministrator()) 
  doSomething();

Có thể được đơn giản hóa thành:

if (currentUser.isAdministrator())
  doSomething ();

Nếu currentUserđược mặc định cho một số 'người dùng ẩn danh' hoặc 'người dùng null' với triển khai dự phòng nếu người dùng không đăng nhập.

Không phải luôn luôn là một mùi mã, nhưng một cái gì đó để xem xét.


-4

Tôi sẽ không được ưa chuộng và nói Có, đó là một thực tế tồi. NẾU chức năng của mã của bạn đang dựa vào nó để thực hiện logic có điều kiện.

I E

 if(quickLogicA && slowLogicB) {doSomething();}

là tốt, nhưng

if(logicA && doSomething()) {andAlsoDoSomethingElse();}

là xấu, và chắc chắn không ai sẽ đồng ý với?!

if(doSomething() || somethingElseIfItFailed() && anotherThingIfEitherWorked() & andAlwaysThisThing())
{/* do nothing */}

Lý do:

Lỗi mã của bạn nếu cả hai bên được đánh giá thay vì chỉ đơn giản là không thực hiện logic. Người ta đã tranh luận rằng đây không phải là vấn đề, toán tử 'và' được định nghĩa trong c # nên ý nghĩa rất rõ ràng. Tuy nhiên, tôi cho rằng điều này không đúng.

Lý do 1. Lịch sử

Về cơ bản, bạn đang dựa vào (mục đích ban đầu là) tối ưu hóa trình biên dịch để cung cấp chức năng trong mã của bạn.

Mặc dù trong c #, đặc tả ngôn ngữ đảm bảo toán tử boolean 'và' không bị đoản mạch. Điều này không đúng với tất cả các ngôn ngữ và trình biên dịch.

wikipeda liệt kê các ngôn ngữ khác nhau và họ sử dụng ngắn mạch http://en.wikipedia.org/wiki/Short-circuit_ev Assessment vì bạn có thể có nhiều cách tiếp cận. Và một vài vấn đề nữa tôi không đi vào đây.

Cụ thể, FORTRAN, Pascal và Delphi có các cờ biên dịch chuyển đổi hành vi này.

Do đó: Bạn có thể thấy mã của mình hoạt động khi được biên dịch để phát hành, nhưng không phải để gỡ lỗi hoặc với trình biên dịch thay thế, v.v.

Lý do 2. Sự khác biệt về ngôn ngữ

Như bạn có thể thấy từ wikipedia, không phải tất cả các ngôn ngữ đều có cùng cách tiếp cận với đoản mạch, ngay cả khi chúng chỉ định cách các toán tử boolean nên xử lý nó.

Cụ thể, toán tử 'và' của VB.Net không bị đoản mạch và TSQL có một số đặc thù.

Cho rằng một 'giải pháp' hiện đại có khả năng bao gồm một số ngôn ngữ, chẳng hạn như javascript, regex, xpath, v.v. bạn nên tính đến điều này khi làm rõ chức năng mã của mình.

Lý do 3. Sự khác biệt trong một ngôn ngữ

Ví dụ: nội tuyến của VB nếu hành xử khác với if. Một lần nữa trong các ứng dụng hiện đại, mã của bạn có thể di chuyển giữa, ví dụ mã phía sau và một biểu mẫu web nội tuyến, bạn phải nhận thức được sự khác biệt về ý nghĩa.

Lý do 4. Ví dụ cụ thể của bạn về việc kiểm tra null tham số của hàm

Đây là một ví dụ rất tốt. Trong đó đó là điều ai cũng làm, nhưng thực tế là thực tế tồi tệ khi bạn nghĩ về nó.

Rất phổ biến để xem loại kiểm tra này vì nó làm giảm đáng kể các dòng mã của bạn. Tôi nghi ngờ bất cứ ai sẽ đưa nó lên trong một đánh giá mã. (và rõ ràng từ các bình luận và đánh giá bạn có thể thấy nó phổ biến!)

Tuy nhiên, nó thất bại thực hành tốt nhất vì nhiều hơn một lý do!

  1. Của nó rất rõ ràng từ nhiều nguồn khác nhau, mà thực hành tốt nhất là để kiểm tra các thông số của bạn cho hiệu lực trước khi bạn sử dụng chúng và để ném một ngoại lệ nếu họ không hợp lệ. Đoạn mã của bạn không hiển thị mã xung quanh, nhưng có lẽ bạn nên làm gì đó như:

    if (smartphone == null)
    {
        //throw an exception
    }
    // perform functionality
    
  2. Bạn đang gọi một hàm từ trong câu lệnh có điều kiện. Mặc dù tên hàm của bạn ngụ ý rằng nó chỉ đơn giản là tính toán một giá trị, nhưng nó có thể ẩn các tác dụng phụ. ví dụ

    Smartphone.GetSignal() { this.signal++; return this.signal; }
    
    else if (smartphone.GetSignal() < 1)
    {
        // Do stuff 
    }
    else if (smartphone.GetSignal() < 2)
    {
        // Do stuff 
    }
    

    thực hành tốt nhất sẽ đề nghị:

    var s = smartphone.GetSignal();
    if(s < 50)
    {
        //do something
    }
    

Nếu bạn áp dụng các thực tiễn tốt nhất này cho mã của mình, bạn có thể thấy rằng cơ hội để đạt được mã ngắn hơn thông qua việc sử dụng các điều kiện ẩn sẽ biến mất. Thực hành tốt nhất là làm một cái gì đó , để xử lý trường hợp điện thoại thông minh là null.

Tôi nghĩ rằng bạn sẽ thấy rằng đây cũng là trường hợp cho các tập quán phổ biến khác. Bạn phải nhớ chúng tôi cũng có:

điều kiện nội tuyến

var s = smartphone!=null ? smartphone.GetSignal() : 0;

và hợp nhất null

var s = smartphoneConnectionStatus ?? "No Connection";

cung cấp chức năng độ dài mã ngắn tương tự với sự rõ ràng hơn

nhiều liên kết để hỗ trợ tất cả các điểm của tôi:

https://stackoverflow.com/questions/1158614/what-is-the-best-practice-in-case-one-argument-is-null

Xác thực tham số của nhà xây dựng trong C # - Thực tiễn tốt nhất

Có nên kiểm tra null nếu anh ta không mong đợi null?

https://msdn.microsoft.com/en-us/l Library / reyhszts% 28v = vs.110% 29.aspx

https://stackoverflow.com/questions/1445867/why-would-a-lingu-not-use-short-circuit-ev Assessment

http://orcharddojo.net/orchard-resource/L Library / DevelopmentD Guide / BestPractices / Sharp

ví dụ về các cờ biên dịch ảnh hưởng đến ngắn mạch:

Fortran: "sce | nosce Theo mặc định, trình biên dịch thực hiện đánh giá ngắn mạch trong các biểu thức logic được chọn bằng quy tắc XL Fortran. Chỉ định sce cho phép trình biên dịch sử dụng quy tắc Fortran không XL. Trình biên dịch sẽ thực hiện đánh giá ngắn mạch nếu quy tắc hiện tại cho phép Mặc định là không rõ ràng. "

Pascal: "B - Một lệnh cờ điều khiển đánh giá ngắn mạch. Xem Thứ tự đánh giá toán hạng của toán tử dyadic để biết thêm thông tin về đánh giá ngắn mạch. Xem thêm tùy chọn trình biên dịch -sc cho trình biên dịch dòng lệnh để biết thêm thông tin ( được ghi lại trong Hướng dẫn sử dụng). "

Delphi: "Delphi hỗ trợ đánh giá ngắn mạch theo mặc định. Nó có thể được tắt bằng cách sử dụng chỉ thị trình biên dịch {$ BOOLEVAL OFF}."


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Kỹ sư thế giới
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.