2009-03-26 32 views
44

Ok, vì vậy tôi đã đọc về vấn đề này một số lần, nhưng tôi chưa nghe, dễ hiểu (và đáng nhớ) cách rõ ràng để tìm hiểu sự khác biệt giữa:Một lời giải thích rõ ràng của giáo dân về sự khác biệt giữa | và || trong C#?

if (x | y) 

if (x || y) 

..với bối cảnh của C#. Bất cứ ai có thể xin vui lòng giúp tôi tìm hiểu sự thật cơ bản này, và làm thế nào C# cụ thể, đối xử với họ một cách khác nhau (vì họ dường như làm điều tương tự). Nếu sự khác biệt một đoạn mã nhất định giữa chúng không liên quan, tôi nên mặc định điều gì là một phương pháp hay nhất?

Trả lời

83

|| là nhà điều hành hợp lý hợp lý hoặc. Xem here. Nó đánh giá thành true nếu ít nhất một trong các toán hạng là đúng. Bạn chỉ có thể sử dụng nó với các toán hạng boolean; nó là một lỗi để sử dụng nó với toán hạng số nguyên.

// Example 
var one = true || bar(); // result is true; bar() is never called 
var two = true | bar(); // result is true; bar() is always called 

| là các nhà điều hành hoặc. Xem here. Nếu áp dụng cho các kiểu boolean, nó sẽ đánh giá thành true nếu ít nhất một trong các toán hạng là đúng. Nếu được áp dụng cho các kiểu số nguyên, nó sẽ đánh giá đến một số khác. Số này có mỗi bit được đặt thành 1 nếu ít nhất một trong các toán hạng có một bộ bit tương ứng.

// Example 
var a = 0x10; 
var b = 0x01; 
var c = a | b;  // 0x11 == 17 
var d = a || b; // Compile error; can't apply || to integers 
var e = 0x11 == c; // True 

Đối với toán hạng boolean, a || bgiống hệt-a | b, với ngoại lệ duy nhất b là không được đánh giá nếu a là đúng. Vì lý do này, || được gọi là "đoản mạch".

Nếu sự khác biệt một đoạn mã nhất định giữa chúng không liên quan, tôi nên đặt mặc định nào là phương pháp hay nhất?

Như đã lưu ý, sự khác biệt không liên quan, vì vậy câu hỏi này là một phần tranh luận. Đối với một "thực hành tốt nhất", không có một: bạn chỉ cần sử dụng bất kỳ nhà điều hành là một trong những chính xác để sử dụng. Nói chung, mọi người ủng hộ || qua | cho các toán hạng boolean vì bạn có thể chắc chắn rằng nó sẽ không tạo ra các tác dụng phụ không cần thiết.

10

Chúng không giống nhau. Một là bitwise OR và một là hợp lý HOẶC.

X || Y, là logic hoặc có nghĩa là "X hoặc Y" và áp dụng cho các giá trị bool. Nó được sử dụng trong các điều kiện hoặc kiểm tra. X và Y trong trường hợp đó có thể được thay thế bằng bất kỳ biểu thức nào đánh giá thành bool. Ví dụ:

if (File.Exists("List.txt") || x > y) { ..} 

Điều khoản đánh giá đúng nếu một trong hai điều kiện là đúng. Nếu điều kiện đầu tiên là đúng (nếu tệp tồn tại), thì điều kiện thứ hai không cần và sẽ không được đánh giá.

Đường ống đơn (|) là bit OR. Để biết điều này có nghĩa là bạn phải hiểu cách số được lưu trữ trong máy tính. Giả sử bạn có một số lượng 16-bit (Int16) chứa giá trị 15. Nó thực sự được lưu trữ dưới dạng 0x000F (trong hex), giống như 0000 0000 0000 1111 trong nhị phân. OR bitwise lấy hai đại lượng và mỗi cặp của các bit tương ứng với nhau, sao cho nếu bit là 1 trong một trong hai đại lượng, thì nó là 1 trong kết quả. Do đó, nếu a = 0101 0101 0101 0101 (đánh giá thành 0x5555 trong hex) và b = 1010 1010 1010 1010 (là 0xAAAA), thì a | b = 1111 1111 1111 1111 = 0xFFFF.

Bạn có thể sử dụng bitwise OR (ống đơn) trong C# để kiểm tra xem một hoặc nhiều bộ bit cụ thể có được bật hay không. Bạn có thể làm điều này nếu bạn có, giả sử, 12 giá trị boolean hoặc nhị phân để kiểm tra và tất cả chúng đều độc lập. Giả sử bạn có một cơ sở dữ liệu sinh viên. Một tập hợp các phép toán độc lập có thể là những thứ như nam/nữ, nhà/trong khuôn viên, hiện tại/không phải hiện tại, đã đăng ký/không ghi danh, v.v. Thay vì lưu trữ trường boolean cho mỗi giá trị đó, bạn có thể lưu trữ chỉ một chút cho mỗi cái. Các nam/nữ có thể là chút 1. đăng ký/không thể có chút 2.

Sau đó, bạn có thể sử dụng

if ((bitfield | 0x0001) == 0x0001) { ... } 

như một thử nghiệm để xem nếu không có bit được bật, ngoại trừ các "học sinh là nam "bit, bị bỏ qua. Huh? Vâng, bitwise OR trả về 1 cho mỗi bit đang ở trong một trong hai số. Nếu kết quả của bitwise OR ở trên = 0x0001, điều đó có nghĩa là không có bit nào được bật trong bitfield, ngoại trừ có thể là bit đầu tiên (0x0001), nhưng bạn không thể chắc chắn liệu bit đầu tiên có bật hay không, bởi vì nó là mặt nạ.

Có một & & và & tương ứng AND và bitwise AND. Họ có hành vi tương tự.

Bạn có thể sử dụng

if ((bitfield & 0x0001) == 0x0001) { ... } 

để xem nếu bit đầu tiên được bật trong một bitfield.

EDIT: Tôi không thể tin rằng tôi đã bỏ phiếu cho điều này!

+0

| có ý nghĩa khác trong C#. Đó có thể là lý do tại sao. – jalf

+1

Thật đáng ngạc nhiên khi bạn đã bình chọn, vì câu trả lời hoàn toàn không liên quan đến câu hỏi ... – Guffa

4

| là toán tử OR bitwise (số, số nguyên). nó hoạt động bằng cách chuyển đổi các số thành nhị phân và thực hiện một OR cho mỗi chữ số tương ứng. sau đó một lần nữa, các con số đã được biểu diễn bằng nhị phân trong máy tính, do đó không có chuyển đổi nào thực sự xảy ra trong thời gian chạy;)

|| là toán tử OR logic (boolean). nó chỉ hoạt động trên các giá trị đúng và sai.

2

Toán tử bitwise đầu tiên hoạt động trên hai giá trị số và kết quả ở giá trị thứ ba.

Nếu bạn có các biến nhị phân

a = 0001001b; 
b = 1000010b; 

sau đó

a | b == 1001011b; 

Đó là, một chút trong kết quả là 1 nếu nó cũng là 1 trong một trong các toán hạng. (Ví dụ của tôi sử dụng số 8 bit vì mục đích rõ ràng)

"ống kép" ||, là toán tử OR hợp lý có hai giá trị boolean và kết quả trong một phần ba.

5

Câu trả lời hay, nhưng hãy để tôi thêm rằng biểu thức bên phải cho || không được đánh giá nếu biểu thức bên trái là true. Hãy ghi nhớ điều này trong trường hợp các điều kiện đánh giá là a) hiệu suất chuyên sâu hoặc b) tạo ra các tác dụng phụ (hiếm).

5

Không giống như hầu hết các câu trả lời cho đến nay, ý nghĩa là không phải giống hệt như trong C++.

Đối với bất kỳ hai biểu thức A và B nào đánh giá thành boolean, A || B và A | B làm gần giống như vậy.

A | B đánh giá cả hai A và B và nếu một trong số đó đánh giá là đúng, kết quả là đúng.

A || B gần như giống nhau, ngoại trừ nó đánh giá A đầu tiên, và sau đó chỉ đánh giá B nếu nó là cần thiết. Vì toàn bộ biểu thức là đúng nếu A hoặc B là đúng, B không cần phải kiểm tra nếu A là đúng. Vì vậy || ngắn mạch, và bỏ qua đánh giá toán hạng thứ hai khi có thể, ở đâu | nhà điều hành sẽ luôn đánh giá cả hai.

| nhà điều hành không thường xuyên được sử dụng, và thường nó sẽ không tạo ra sự khác biệt. Trường hợp thông thường duy nhất tôi có thể nghĩ đến việc nó tạo nên sự khác biệt ở đâu là:

if (foo != null || foo.DoStuff()){ // assuming DoStuff() returns a bool 

} 

Điều này làm việc vì hàm thành viên DoStuff() không bao giờ được gọi nếu thử nghiệm trái không thành công. Tức là, nếu foo là null, chúng ta không gọi DoStuff trên nó. (mà sẽ cho chúng ta một NullReferenceException).

Nếu chúng tôi đã sử dụng | toán tử, DoStuff() sẽ được gọi bất kể foo là null hay không.

Trên số nguyên, chỉ | toán tử được định nghĩa, và là một bitwise OR, như các câu trả lời khác mô tả. || toán tử không được định nghĩa cho các kiểu số nguyên mặc dù vậy, rất khó để có được chúng hỗn hợp trong C#.

+0

Mã bạn đã viết không chính xác. Biểu mẫu chính xác là: 'if (foo == null || foo.DoStuff())'. Vì vậy, nếu 'foo == null', biểu thức trả về' true' mà không đánh giá thêm; nếu không 'foo' không phải là null vì vậy phần đầu tiên trả về false và phần thứ hai được đánh giá và có thể vì trong trường hợp này' foo' không phải là null. –

3

Sau đây sẽ làm việc trong C/C++ bởi vì nó không có hỗ trợ lớp đầu tiên cho booleans, nó xử lý mọi biểu thức với bit "on" trên chúng là true false. Trong thực tế, đoạn mã sau sẽ không hoạt động trong C# hoặc Java nếu x và y thuộc loại số.

if (x | y) 

Vì vậy, các phiên bản rõ ràng mã trên là:

if ((x | y) != 0) 

Trong C, bất kỳ biểu hiện đó sẽ có một "On" chút về họ, kết quả là true

int i = 8 ;

nếu (i) // hợp lệ trong C, kết quả là đúng

int joy = -10;

if (niềm vui) // vaild trong C, kết quả là true

Bây giờ, trở lại C#

Nếu x và y là kiểu số, mã của bạn: if (x | y) sẽ không làm việc. Bạn đã thử biên dịch chưa? Nó sẽ không hoạt động

Nhưng đối với mã của bạn, mà tôi có thể giả định x và y là các loại boolean, do đó, nó sẽ làm việc, do đó, sự khác biệt giữa | và || đối với các kiểu boolean, || ngắn mạch, | không phải là.Kết quả các nội dung sau:

static void Main() 
    { 


     if (x | y) 
      Console.WriteLine("Get"); 

     Console.WriteLine("Yes"); 

     if (x || y) 
      Console.WriteLine("Back"); 

     Console.ReadLine(); 
    } 


    static bool x 
    { 
     get { Console.Write("Hey"); return true; } 
    } 

    static bool y 
    { 
     get { Console.Write("Jude"); return false; } 
    } 

là:

HeyJudeGet 
Yes 
HeyBack 

Jude sẽ không được in hai lần, || là toán tử boolean, nhiều toán tử boolean có nguồn gốc từ C là ngắn mạch được lưu hành, biểu thức boolean có hiệu suất cao hơn nếu chúng được đoản mạch.

Đối với thuật ngữ người thường, khi bạn nói ngắn mạch, ví dụ: || (hoặc toán tử), nếu biểu thức đầu tiên đã đúng, không cần đánh giá biểu thức thứ hai. Ví dụ: if (answer == 'y' || answer == 'Y'), nếu người dùng nhấn y nhỏ, chương trình không cần đánh giá biểu thức thứ hai (answer == 'Y'). Đó là ngắn mạch.

Trên mã mẫu của tôi ở trên, X là đúng, vì vậy Y trên || toán tử sẽ không được đánh giá thêm, do đó không có đầu ra "Jude" thứ hai.

Không sử dụng loại mã này trong C# ngay cả khi X và Y thuộc loại boolean: nếu (x | y). Không biểu diễn.

42

Khi sử dụng với toán hạng boolean các nhà điều hành | là một toán tử logic giống như ||, nhưng sự khác biệt là các nhà điều hành || không đánh giá ngắn mạch và các nhà điều hành | không.

Điều này có nghĩa là toán hạng thứ hai luôn được đánh giá bằng toán tử |, nhưng sử dụng toán tử || toán hạng thứ hai chỉ được đánh giá nếu toán hạng đầu tiên đánh giá sai.

Kết quả của biểu thức luôn giống nhau cho cả hai phép toán, nhưng nếu việc đánh giá toán hạng thứ hai sẽ làm thay đổi điều gì đó, điều đó chỉ đảm bảo xảy ra nếu bạn sử dụng toán tử |.

Ví dụ:

int a = 0; 
int b = 0; 

bool x = (a == 0 || ++b != 0); 

// here b is still 0, as the "++b != 0" operand was not evaluated 

bool y = (a == 0 | ++b != 0); 

// here b is 1, as the "++b != 0" operand was evaluated. 

Việc đánh giá ngắn mạch của các nhà điều hành || có thể được sử dụng để viết mã ngắn hơn, như các toán hạng thứ hai chỉ được đánh giá nếu toán hạng đầu tiên là đúng. Thay vì viết như thế này:

if (str == null) { 
    Console.WriteLine("String has to be at least three characters."); 
} else { 
    if (str.Length < 3) { 
     Console.WriteLine("String has to be at least three characters."); 
    } else{ 
     Console.WriteLine(str); 
    } 
} 

Bạn có thể viết như thế này:

if (str == null || str.Length < 3) { 
    Console.WriteLine("String has to be at least three characters."); 
} else{ 
    Console.WriteLine(str); 
} 

Các toán hạng thứ hai chỉ được đánh giá nếu là người đầu tiên là sai, vì vậy bạn có biết rằng bạn có thể yên tâm sử dụng tham chiếu chuỗi trong toán hạng thứ hai vì nó không thể null nếu toán hạng thứ hai được đánh giá.

Trong hầu hết các trường hợp, bạn sẽ muốn sử dụng toán tử || thay vì toán tử |. Nếu toán hạng đầu tiên là false, không cần đánh giá toán hạng thứ hai để nhận kết quả. Ngoài ra, rất nhiều người (rõ ràng) không biết rằng bạn có thể sử dụng toán tử | với toán hạng boolean, vì vậy chúng sẽ bị lẫn lộn khi nhìn thấy nó được sử dụng theo cách đó trong mã.

+3

Ước gì tôi có thể cho +10, đây là câu trả lời phù hợp nhất liên quan đến C#. Trong khi tất cả những người khác là chính xác về mặt kỹ thuật, họ bỏ qua thực tế là câu hỏi liên quan đến logic boolean trong C#. –

+0

Không nên là "str! = Null"? – Les

+0

Không, phần đó là chính xác, nhưng phần đầu tiên có vẻ sai với tôi: int a = 0; int b = 0; bool x = (a! = 0 || ++ b! = 0); // tại đây b vẫn bằng 0, vì toán hạng "++ b! = 0" không được đánh giá Nhưng một == 0, do đó câu lệnh đầu tiên được đánh giá là sai và do đó phần thứ hai được đánh giá. – Davy8

2

Nếu không tìm hiểu chi tiết bằng bất kỳ cách nào, hình dạng hoặc hình thức, đây là phiên bản của người phiên bản thực.

Hãy suy nghĩ về "|" thẳng thắn "hoặc" bằng tiếng Anh; nghĩ về "||" là "hoặc người nào khác" bằng tiếng Anh.

Tương tự, hãy nghĩ đến "&" dưới dạng "và" bằng tiếng Anh; hãy nghĩ đến "& &" dưới dạng "và cả" bằng tiếng Anh.

Nếu bạn đọc một biểu thức cho chính mình bằng các cụm từ này, chúng thường có ý nghĩa hơn rất nhiều.

1

Mặc dù nó đã được nói và trả lời một cách chính xác Tôi nghĩ rằng tôi muốn thêm một câu trả lời của giáo dân thực sự vì rất nhiều thời gian đó là những gì tôi cảm thấy như trên trang web này :). Ngoài ra, tôi sẽ thêm ví dụ về & so với & & vì nó là cùng một khái niệm

| so với ||

Về cơ bản, bạn có xu hướng sử dụng || khi bạn chỉ wnat để đánh giá phần thứ hai NẾU phần đầu tiên nó FALSE. Vì vậy, đây:

if (func1() || func2()) {func3();} 

cũng giống như

if (func1()) 
{ 
    func3(); 
} 
else 
{ 
    if (func2()) {func3();} 
} 

Đây có thể là một cách để tiết kiệm thời gian chế biến. Nếu func2() mất nhiều thời gian để xử lý, bạn sẽ không muốn thực hiện nếu func1() đã đúng.

& vs & &

Trong trường hợp của & vs & & đó là một tình huống tương tự, nơi bạn chỉ đánh giá phần thứ hai NẾU phần đầu tiên là TRUE. Ví dụ này:

if (func1() && func2()) {func3();} 

cũng giống như

if (func1()) 
{ 
    if (func2()) {func3();}} 
} 

Đây có thể là cần thiết vì Func2() có thể phụ thuộc vào Func1() đầu tiên là sự thật. Nếu bạn đã sử dụng & và func1() được đánh giá là sai, & sẽ chạy func2() anyways, điều này có thể gây ra lỗi thời gian chạy.

Jeff các Layman

2

Đề nghị đọc this bài báo từ Dotnet Mob

Đối OR logic nếu có của nó toán hạng được đánh giá là true thì toàn bộ biểu hiện được đánh giá là true

đây là những gì || Nhà điều hành không - nó bỏ qua các đánh giá còn lại khi nó tìm thấy một sự thật. Trong khi | Toán tử đánh giá toán hạng đầy đủ của nó để xác định giá trị của toàn bộ biểu thức.

if(true||Condition1())//it skip Condition1()'s evaluation 
{ 
//code inside will be executed 
} 
if(true|Condition1())//evaluates Condition1(), but actually no need for that 
{ 
//code inside will be executed 
} 

Nó là tốt hơn để sử dụng ngắn mạch phiên bản của toán tử logic Cho dù đó là OR (||) hoặc AND (& &) điều hành.


Hãy xem xét đoạn mã sau

int i=0; 
if(false||(++i<10))//Now i=1 
{ 
//Some Operations 
} 
if(true||(++i<10))//i remains same, ie 1 
{} 

Hiệu ứng này được gọi là phía tác, thực sự nhìn thấy ở phía bên phải của biểu thức trong toán tử logic mạch ngắn

tham khảo: Short-circuit Evaluation in C#

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