В чем разница между 'foo = Nothing' и 'foo is Nothing' в VB.NET? - PullRequest
10 голосов
/ 25 июня 2010

В VB.NET , в чем разница между

if foo is Nothing Then
      doStuff()
End If

и

if foo=Nothing Then
    doStuff()
End If
<Ч />

Обновление Я получил следующий ответ:

foo is Nothing просто проверяет, не присвоено ли foo какой-либо ссылке. foo = Nothing проверяет, равна ли ссылка, удерживаемая foo, nothing.

После выполнения трех операторов

Dim foo as Object
Dim bar as Integer
foo = bar

foo is Nothing оценивается как ложное, а foo = Nothing оценивается как истинное.

Однако, если bar объявлен как Object и не инициализирован, тогда foo is Nothing и foo = Nothing оба будут иметь значение true! Я думаю, это потому, что Integer является типом значения, а Object является ссылочным типом.

Ответы [ 6 ]

11 голосов
/ 25 июня 2010

Это зависит от типа.

  • Для типов значений , Is не работает , только =Nothing относится к экземпляру по умолчанию этого типа (т. е. к экземпляру, который вы получаете, вызывая New T() для данного типа T).

  • Для ссылки типы , Is выполняют сравнение ссылок (идентично object.ReferenceEquals(a, Nothing)).a = Nothing обычно не работает , , если для этого класса явно не определено Operator =.

    Если, кроме того, Operator = реализован правильно,тогда foo = Nothing и foo Is Nothing должны дать тот же результат (но то же самое не верно для любого другого значения вместо Nothing), но foo Is Nothing будет более эффективным, поскольку это присуще компилятору, тогда как Operator = вызоветa метод.

  • Для типов значений, допускающих значение NULL (т.е. экземпляры Nullable(Of T)), применяются специальные правила: как и все другие операторы, = равен поднял (обратите внимание на ошибку в этом сообщении в блоге ...) компилятором для базового типа.Таким образом, результат сравнения двух Nullable с будет не Boolean, а Boolean? (обратите внимание на ?).Однако из-за так называемого «нулевого распространения» для поднятых операторов, это будет всегда возвращать Nothing, независимо от значения foo.Цитируя спецификацию языка Visual Basic 10 (§1.86.3):

    Если операндом ether (sic!) Является Nothing, результатом выражения будет значениеNothing набирается как обнуляемая версия типа результата.

    Поэтому, если пользователи хотят сравнить переменную Nullable с Nothing, они должны использовать синтаксис foo Is Nothing, для которого,еще раз, компилятор генерирует специальный код, чтобы заставить его работать (§1.79.3 спецификации языка Visual Basic 10). Шляпа Джонатану Аллену за то, что (правильно) настаивает, что я ошибался;передайте Джареду Парсонсу ссылку на спецификацию Visual Basic 10.

(Выше предполагается, что используется Option Strict On, поскольку вы всегда должен. В случае, если это не так, результаты будут немного отличаться, так как вызов foo = Nothing может выполнить вызов с поздним связыванием.)

3 голосов
/ 25 июня 2010
foo is Nothing simply checks if `foo` is not assigned to any reference.

foo=Nothing checks if the reference held by `foo` is equal to `nothing`

В VB оба оператора будут иметь одинаковое значение, если foo не был инициализирован

2 голосов
/ 25 июня 2010

Вот несколько IL, чтобы проверить различия:

.method public static void Main() cil managed
{
    .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
    .entrypoint
    .maxstack 3
    .locals init (
        [0] object o,
        [1] bool VB$CG$t_bool$S0)
    L_0000: nop 
    L_0001: newobj instance void [mscorlib]System.Object::.ctor()
    L_0006: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)
    L_000b: stloc.0 
    L_000c: ldloc.0 
    L_000d: ldnull 
    L_000e: ceq 
    L_0010: stloc.1 
    L_0011: ldloc.1 
    L_0012: brfalse.s L_001f
    L_0014: ldstr "Is Nothing"
    L_0019: call void [mscorlib]System.Console::WriteLine(string)
    L_001e: nop 
    L_001f: nop 
    L_0020: ldloc.0 
    L_0021: ldnull 
    L_0022: ldc.i4.0 
    L_0023: call bool [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::ConditionalCompareObjectEqual(object, object, bool)
    L_0028: stloc.1 
    L_0029: ldloc.1 
    L_002a: brfalse.s L_0037
    L_002c: ldstr "Is nothing"
    L_0031: call void [mscorlib]System.Console::WriteLine(string)
    L_0036: nop 
    L_0037: nop 
    L_0038: nop 
    L_0039: ret 
}

VB код:

Sub Main()
        Dim o As New Object

        If o Is Nothing Then
            Console.WriteLine("Is Nothing")
        End If

        If o = Nothing Then
            Console.WriteLine("Is nothing")
        End If
    End Sub
1 голос
/ 28 июня 2010

Зависит от типа Фу.

Типы ссылок

if foo = Nothing then 'This depends on how the op_Equals operator is defined for Foo. If not defined, then this is a compiler error. 
if foo Is Nothing then 'Evaluates to True is foo is NULL

Типы значений

if foo = Nothing then 'Evaluates to True is foo has the default value in every field. For most types the default is 0.
if foo Is Nothing then 'Compiler Error

Типы значений Nullable

if foo = Nothing then 'This always evaluates to false. In VB 10, this is a compiler warning
if foo Is Nothing then 'Evaluates to True is foo.HasValue = False

Многие люди не понимают Нулевого Распространения в VB. Как и SQL, он использует трехзначную логику, поэтому ответом на «a = b» может быть True, False или Null. В операторе If значение Null считается ложным.

Предупреждение Вы не можете просто написать If Not(Foo = Nothing) Then, потому что 'Not (Nothing)' по-прежнему 'Nothing'.

1 голос
/ 27 июня 2010

Asume:

MyFunc (Foo как объект)

Foo - в штучной упаковке, если ValueType

, если foo равен Nothing, тогда

object.ReferenceEquals (Code Inlined - метод Fastest)

if foo = Nothing Then

Operators.ConditionalCompareObjectEqual (foo, Nothing, False)

Vb.Net переносит этот случай как Obj1 = Obj2.Он не использует Obj.equals (obj2)!Исключение, если Obj1 - ничто

Эта опция использует очень сложный код, так как есть много опций, зависящих от всех возможных определений foo.

попробуйте это:

Sub Main()
  Dim o As Object = 0
  Debug.Print(o Is Nothing)  'False
  Debug.Print(o = Nothing)   'True 
End Sub
1 голос
/ 25 июня 2010

foo - указатель на ячейку памяти, и ничто не означает «не указывать ни на какую память, потому что память еще не выделена».Равно означает, что при сравнении двух типов значений они имеют одинаковое значение.Но вы предполагаете, что foo представляет объект, который всегда является ссылочным типом, который должен указывать на объект в памяти.«is» предназначен для сравнения типов объектов и возвращает «true», только если два объекта указывают на одно и то же значение.

Скажем, у вас есть clsFoo с одной общедоступной целочисленной переменной-членом 'x', а foo1 и foo2 оба являются clsFoo, а y и z являются целыми числами

foo1=new clsFoo
foo2=new clsFoo
foo1.x=1
foo2.x=1
y=2
z=1
dim b as boolean 

b= foo1 is not foo2  ' b is true
b= foo1.x=foo2.x ' b is tree
b= foo1 is foo2 'b is false  
b= foo1.x=z ' true of course
foo2.x=3
b= foo1.x=foo2.x ' false of course
foo1=foo2
b=foo1 is foo2 ' now it's true
b= foo1.x=foo2.x ' true again
b= 3=3 ' just as this would be
b= foo1=foo2 ' ERROR: Option Strict On disallows operands of type Object for operator '='. Use the 'Is' operator to test for object identity.

НИКОГДА забудьтевключить опцию строго.Чтобы потерпеть неудачу, это кричит «ПОЖАЛУЙСТА, заставь мою программу сосать».

...