Или против OrElse
Какая разница между или и OrElse?
if temp is dbnull.value or temp = 0
выдает ошибку:
Оператор '=' не определен для типа 'DBNull' и типа 'Integer'.
а этот работает как шарм!?
if temp is dbnull.value OrElse temp = 0
8 ответов
OrElse
является оператором короткого замыкания, Or
не является.
По определению логического оператора 'или', если первый член имеет значение True, тогда целое определенно верно, поэтому нам не нужно оценивать второй член.
OrElse
знает это, поэтому не пытается оценить temp = 0
как только будет установлено, что temp Is DBNull.Value
Or
не знает этого и всегда будет пытаться оценить оба термина. когда temp Is DBNull.Value
, он не может быть сравнен с нулем, поэтому он падает.
Вы должны использовать... ну, какой бы ни имел смысл.
Это то же самое поведение, что и в C#, где каждый использует Coditional Or (||) и Условное And (&&), где у вас также есть нормальное Or (|) и нормальное And (&). Таким образом, сравнение C# с VB.Net выглядит так:
| => Или
|| => OrElse
& => И
&& => AndAlso
Условные булевы операторы очень полезны для предотвращения вложенных if-конструкций. Но иногда необходимы нормальные логические операторы для обеспечения попадания в оба пути кода.
OrElse имеет короткое замыкание, это означает, что только одна сторона выражения будет проверена, если первая сторона совпадает.
Точно так же, как AndAlso будет проверять только одну сторону выражения, если первая половина не удалась.
OrElse вычисляет первое выражение, затем, если оно истинно, оно переходит к оператору, в то время как OR вычисляет два выражения, прежде чем перейти к их выражению.
Пример:
Textbox1.Text= 4
Textbox2.Text= ""
Использование OrElse
If TextBox1.Text > 2 OrElse TextBox2.Text > 3 Then
MsgBox("True")
End If
Результат: ИСТИНА
Используя ИЛИ
If TextBox1.Text > 2 Or TextBox2.Text > 3 Then
MsgBox("True")
End If
Результат: Ошибка не может преобразовать строку в двойную.
(Я посмотрел на другие ответы и понял, что был ужасно неправ)
Оператор OrElse "выполняет короткое замыкание логического дизъюнкции для двух выражений", то есть: если левый операнд истинен и поэтому все выражение гарантированно истинно, правый операнд даже не будет оцениваться (это полезно в случаи как:
string a;
//...
if (a is null) or (a = "Hi") //...
чтобы избежать выброса NullReferenceException правым операндом.
Я искренне удивлен, что это (ленивая оценка) не является поведением по умолчанию or
а также and
как это происходит в C/C++ и C# (и многих других языках...)
Ответ Берта не очень точный. '|' или '&' - логический оператор, в C # он всегда обрабатывается как битовый оператор, см. следующий код в качестве примера
static void Main()
{
object a = null;
int b = 3;
if (a == null | a.ToString() == "sdffd")
{
Console.WriteLine("dddd");
}
Console.WriteLine(b | b);
Console.Read();
}
Следующее является 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
когда вы используете || чтобы проверить "a == null" и "a.ToString() == "sdffd", IL будет
.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
Теперь вы можете увидеть разницу, пожалуйста, не думайте, что '|' или 'и' как условный оператор, это просто логический оператор, я не думаю, что есть необходимость использовать его для оценки условия
Причиной сбоя компиляции в примере является порядок операций.
Парсер выражений пытается сначала оценить "dbnull.value или temp".
if temp is (dbnull.value or temp) = 0
Ошибка здесь, потому что вы не можете сделать побитовое ИЛИ между целым числом (temp) и dbnull.value.
OrElse исправляет это не потому, что он замкнут накоротко, а потому, что он ниже по порядку операций, и поэтому сначала выполняются вычисления "temp is dbnull.value" и "3=0", а не анализатор, пытающийся сравнить dbNull и температура
Таким образом, оценка с OrElse работает так, как вы ожидаете: (предположим, 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
Это было на вступительном экзамене в компании-разработчике, в которой я работал, и это была общая проблема, с которой я сталкивался в VB6. Так что это хорошая идея заключить в скобки ваши подвыражения при использовании логических операторов:
Это было бы правильно скомпилировано:
if (temp is dbnull.value) Or (temp = 0) then
Хотя, как все уже указывали, OrElse и AndAlso действительно правильные операторы для использования в этом контексте.
Если ваша кодовая логика не требует короткого замыкания, которое обеспечивает OrElse, я бы склонялся к использованию оператора Or, потому что:
- Использовать "или" просто и требует меньше печатать.
- Экономия времени при использовании OrElse в большинстве случаев незначительна.
- Самое важное, что использование OrElse может скрыть ошибки в последующих предложениях, которые могут быть изначально не выявлены, пока эти условия не будут в конечном итоге соблюдены логикой программы.