Hoặc so với OrElse


94

Sự khác biệt giữa or và OrElse là gì?

if temp is dbnull.value or temp = 0

tạo ra lỗi:

Toán tử '=' không được định nghĩa cho loại 'DBNull' và loại 'Số nguyên'.

trong khi cái này hoạt động như một sự quyến rũ !?

if temp is dbnull.value OrElse temp = 0

Câu trả lời:


144

OrElselà một nhà điều hành đoản mạch , Orkhông phải.

Theo định nghĩa của toán tử boolean 'hoặc', nếu số hạng đầu tiên là True thì toàn bộ chắc chắn đúng - vì vậy chúng ta không cần đánh giá số hạng thứ hai.

OrElsebiết điều này, vì vậy không thử và đánh giá temp = 0khi nó được thiết lậptemp Is DBNull.Value

Orkhông biết điều này và sẽ luôn cố gắng đánh giá cả hai điều khoản. Khi temp Is DBNull.Value, nó không thể được so sánh với số không, vì vậy nó rơi xuống.

Bạn nên sử dụng ... tốt, cái nào có lý.


2
Vì vậy, Hoặc chỉ có ý nghĩa khi tôi gọi một hàm sau hoặc hàm đó có tác dụng phụ mà mã của tôi phụ thuộc vào?
— Ralph M. Rickenbach 23-07-09

4
Hoặc có ý nghĩa trong mọi trường hợp khi mục thứ hai không kích hoạt lỗi nếu mục đầu tiên là đúng ...
— awe

4
@ malach: Tôi cho là vậy (bạn thực sự nhận được hành vi OrElse làm mặc định trong hầu hết các ngôn ngữ khác): Không phải là ý kiến ​​hay khi gọi các hàm có tác dụng phụ trong điều kiện ghép, nó làm cho mã không thể đọc được.
— Utaal

4
@ awe: vâng, nhưng tại sao bạn thậm chí muốn lãng phí thời gian để đánh giá một thứ mà theo định nghĩa sẽ không thay đổi kết quả của biểu thức?
— Utaal

3
@MarkJ: Tôi không thực sự nghĩ rằng bốn ký tự phụ làm gián đoạn khả năng đọc. Mặt khác, sử dụng một toán tử phụ thuộc vào sự tồn tại của các hiệu ứng phụ (như malach đã viết) để trở thành những âm thanh có ý nghĩa giống như một ý tưởng tồi (và có thể làm cho khả năng đọc khó hơn!). Tôi sẽ coi những tác dụng phụ ở những nơi như vậy là điều không nên, và không thể nghĩ đến bất kỳ tình huống nào mà tôi thích "Or" hơn "OrElse". Thật đáng tiếc khi các toán tử này hoạt động theo cách này, vì hành vi "OrElse" có lẽ là điều được mong đợi nhất ngay cả khi sử dụng "Or" (đặc biệt là khi đến từ các ngôn ngữ khác).
— Kjartan

42

Đây là hành vi tương tự như với C #, nơi mọi người sử dụng Coditional Or (||) và Conditional And (&&), nơi bạn cũng có Or (|) và And (&) bình thường. Vì vậy, so sánh C # với VB.Net là:

| => Hoặc

|| => OrElse

& => Và

&& => AndAlso

Các toán tử boolean condifitonal rất hữu ích trong việc ngăn chặn các cấu trúc if lồng nhau. Nhưng đôi khi các toán tử boolean bình thường là cần thiết để đảm bảo đánh được cả hai đường dẫn mã.


9
Tôi không bao giờ thực sự biết điều này có sẵn. Cảm ơn thông tin mới. Thật tốt khi biết, mặc dù tôi thực sự không thể thấy bất kỳ tình huống nào mà tôi muốn sử dụng "|". Tôi nghĩ rằng nó sẽ yêu cầu điều kiện thứ hai để gây ra các tác dụng phụ có ý nghĩa gì, và bản thân điều đó không có ý nghĩa gì theo ý kiến ​​của tôi! ;)
— Kjartan

7
Eh, theo như tôi biết, |và &là toán tử bit trong C #, không phải là phép toán boolean.
— Nyerguds

8

OrElse bị đoản mạch , điều này có nghĩa là chỉ một mặt của biểu thức sẽ được kiểm tra nếu mặt đầu tiên trùng khớp.

Giống như AndAlso sẽ chỉ kiểm tra một bên của biểu thức nếu nửa đầu không thành công.


4

(Tôi đã xem các câu trả lời khác và nhận ra mình đã sai rất nhiều)

Toán tử OrElse "thực hiện ngắt mạch logic ngắn mạch trên hai biểu thức", nghĩa là: nếu toán hạng bên trái là true và do đó toàn bộ biểu thức được đảm bảo là đúng thì toán hạng bên phải thậm chí sẽ không được đánh giá (điều này hữu ích trong các trường hợp như:

string a;
//...
if (a is null) or (a = "Hi") //...

để tránh một NullReferenceException ném bởi toán hạng bên phải.

Tôi thực sự ngạc nhiên rằng điều này ( đánh giá lười biếng ) không phải là hành vi mặc định của orvà andgiống như trong C / C ++ và C # (và nhiều ngôn ngữ khác ...)


7
Vấn đề là, trong VB classic, chỉ có And và Or, không gây chập mạch. Tôi nghĩ rằng tôi đúng khi nói rằng các bản beta đầu tiên của VB.NET thực sự đã thay đổi hành vi của các toán tử này - có sự náo động, vì vậy chúng đã được thay đổi trở lại và AndAlso và OrElse (đoản mạch) đã được giới thiệu. Tôi chỉ có thể tưởng tượng những cái tên thay thế họ phải xem xét nếu những chính là những người đã tốt nhất ...
— AakashM

1
Bằng cách cung cấp Or và OrElse (| và || trong C #), điều này cho phép nhà phát triển chọn cách họ xử lý mã của riêng mình. Sử dụng đoạn mã trên, tôi sẽ phải sử dụng thử bắt xung quanh nó để xử lý giá trị null trong biến a. OrElse cho phép nhà phát triển xử lý điều này trong câu lệnh if khác như một kết quả có thể biết trước chứ không phải là một ngoại lệ. Đây là rõ ràng hơn nếu biến một là một tham số trong một phương pháp, nơi bạn có ít quyền kiểm soát khi biến được gán một giá trị (tức là bên ngoài phương thức)
— Kevin Hogg

Ngắn mạch cũng không phải là hành vi mặc định của OR và AND trong c #. c # có hai toán tử khác nhau cho các phép toán bit và logic / đoản mạch. && và || thực hiện so sánh logic và trả về giá trị boolean & và | toán tử là bitwise và trả về một giá trị nguyên. Vậy đâu 1 || 2 trả về "true", 1 | 2 trả về "3".
— TomXP411

4

OrElse đánh giá biểu thức đầu tiên, sau đó nếu nó đúng, nó sẽ chuyển sang câu lệnh trong khi OR đánh giá hai biểu thức trước khi nó sẽ tiếp tục câu lệnh của chúng.

Thí dụ:

Textbox1.Text= 4

Textbox2.Text= ""

Sử dụng OrElse

  If TextBox1.Text > 2 OrElse TextBox2.Text > 3 Then
      MsgBox("True")
  End If

Kết quả là: TRUE


Sử dụng HOẶC

 If TextBox1.Text > 2 Or TextBox2.Text > 3 Then

            MsgBox("True")
  End If

Kết quả là: Lỗi không thể chuyển chuỗi thành kép.


3

Câu trả lời của Bert không chính xác lắm. Dấu '|' hoặc '&' là toán tử logic, trong C #, nó luôn được coi là toán tử bit, vui lòng xem đoạn mã sau làm ví dụ

        static void Main()
        {
            object a = null;
            int b = 3;
            if (a == null | a.ToString() == "sdffd")
            {
                Console.WriteLine("dddd");
            }
            Console.WriteLine(b | b);
            Console.Read();
        }

Sau đây là IL

    .method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       62 (0x3e)
  .maxstack  3
  .locals init ([0] object a,
           [1] int32 b,
           [2] bool CS$4$0000)
   IL_0000:  nop
   IL_0001:  ldnull
   IL_0002:  stloc.0
   IL_0003:  ldc.i4.3
   IL_0004:  stloc.1
   IL_0005:  ldloc.0
   IL_0006:  ldnull
   IL_0007:  ceq
   IL_0009:  ldloc.0
   IL_000a:  callvirt   instance string [mscorlib]System.Object::ToString()
   IL_000f:  ldstr      "sdffd"
   IL_0014:  call       bool [mscorlib]System.String::op_Equality(string,
                                                                 string)
   IL_0019:  or
   IL_001a:  ldc.i4.0
   IL_001b:  ceq
   IL_001d:  stloc.2
   IL_001e:  ldloc.2
   IL_001f:  brtrue.s   IL_002e
   IL_0021:  nop
   IL_0022:  ldstr      "dddd"
   IL_0027:  call       void [mscorlib]System.Console::WriteLine(string)
   IL_002c:  nop
   IL_002d:  nop
   IL_002e:  ldloc.1
   IL_002f:  ldloc.1
   IL_0030:  or
   IL_0031:  call       void [mscorlib]System.Console::WriteLine(int32)
   IL_0036:  nop
   IL_0037:  call       int32 [mscorlib]System.Console::Read()
   IL_003c:  pop
   IL_003d:  ret
    } // end of method Program::Main

khi bạn sử dụng || để kiểm tra "a == null" và "a.ToString () ==" sdffd ", IL sẽ là

 .method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       63 (0x3f)
  .maxstack  2
  .locals init ([0] object a,
           [1] int32 b,
           [2] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldc.i4.3
  IL_0004:  stloc.1
  IL_0005:  ldloc.0
  IL_0006:  brfalse.s  IL_001d
  IL_0008:  ldloc.0
  IL_0009:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_000e:  ldstr      "sdffd"
  IL_0013:  call       bool [mscorlib]System.String::op_Equality(string,
                                                                 string)
  IL_0018:  ldc.i4.0
  IL_0019:  ceq
  IL_001b:  br.s       IL_001e
  IL_001d:  ldc.i4.0
  IL_001e:  stloc.2
  IL_001f:  ldloc.2
  IL_0020:  brtrue.s   IL_002f
  IL_0022:  nop
  IL_0023:  ldstr      "dddd"
  IL_0028:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_002d:  nop
  IL_002e:  nop
  IL_002f:  ldloc.1
  IL_0030:  ldloc.1
  IL_0031:  or
  IL_0032:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_0037:  nop
  IL_0038:  call       int32 [mscorlib]System.Console::Read()
  IL_003d:  pop
  IL_003e:  ret
} // end of method Program::Main

Bây giờ bạn có thể thấy sự khác biệt, xin đừng nghĩ đến dấu '|' hoặc 'và' như một toán tử điều kiện, nó chỉ là một toán tử logic, tôi không nghĩ rằng cần phải sử dụng nó để đánh giá điều kiện


2
The '|' or '&' is logical operator, in C #, it always treat as bit operator. Tôi cũng tin vào điều này, cho đến khi tôi thấy tài liệu tham khảo này, msdn.microsoft.com/en-us/library/kxszd0kx.aspx
— user3207158

Câu trả lời của bạn nằm ngoài ngữ cảnh. Câu hỏi không liên quan đến C # mà là VB trong đó bốn toán tử logic: And, AndAlso, Or, OrElse, Not, và Xor đều là toán tử logic và Bitwise.
— Jean-François

0

Trừ khi logic mã của bạn yêu cầu hành vi đoản mạch mà OrElse cung cấp, tôi sẽ nghiêng về việc sử dụng toán tử Or vì:

  • Sử dụng "Or" rất đơn giản và ít phải nhập.
  • Tiết kiệm thời gian tính toán khi sử dụng OrElse là không đáng kể trong hầu hết các trường hợp.
  • Quan trọng nhất, sử dụng OrElse có thể ẩn các lỗi trong các mệnh đề sau này mà ban đầu có thể không được tiết lộ cho đến khi các điều kiện đó cuối cùng được logic chương trình đáp ứng.

0

Lý do biên dịch không thành công trong ví dụ là thứ tự của các hoạt động.

Trình phân tích cú pháp biểu thức đang cố gắng đánh giá "dbnull.value hoặc temp" trước.

if temp is (dbnull.value or temp) = 0

Lỗi là ở đây, bởi vì bạn không thể thực hiện một chút HOẶC giữa một số nguyên (tạm thời) và dbnull.value.

OrElse sửa lỗi này, không phải vì nó bị đoản mạch, mà vì nó thấp hơn về thứ tự hoạt động và do đó "temp là dbnull.value" và "3 = 0" đang được đánh giá đầu tiên, thay vì trình phân tích cú pháp cố gắng so sánh dbNull và nhiệt độ.

Vì vậy, đánh giá với OrElse hoạt động như bạn đang mong đợi: (giả sử temp = 3)

if temp is dbnull.value OrElse temp = 0 then
if 3 is dbnull.value OrElse 3 = 0 then
if false OrElse 3=0 then
if false OrElse false then
if false then

Đây thực sự là một bài kiểm tra đầu vào tại một công ty phần mềm mà tôi từng làm việc và đó là một vấn đề phổ biến mà tôi từng gặp trong VB6. Vì vậy, bạn nên đặt dấu ngoặc đơn cho các biểu thức con khi sử dụng toán tử boolean:

Điều này sẽ được biên dịch đúng cách:

if (temp is dbnull.value) Or (temp = 0) then 

Mặc dù, như mọi người đã chỉ ra, OrElse và AndAlso thực sự là những toán tử chính xác để sử dụng trong ngữ cảnh này.

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 cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.