Почему порядок операндов имеет значение при тестировании свойства PSCustomObject - PullRequest
0 голосов
/ 03 сентября 2018

Я пробовал оба случая $psCustomObject.x -eq $null и $null -eq $psCustomObject.x в операторе if, и только последний передал оператор if. Почему это ведет себя так? Это кажется нелогичным.

Мой конкретный пример использования - это файл json, который содержит конфигурации для нескольких сред. Имя среды является ключевым в объекте, моя цель - уведомить пользователя, когда нацелена несуществующая среда (возможно, опечатка), и затем остановиться.

Я не хотел использовать! opreator, потому что он имеет чрезвычайно высокое отношение информации к коду - его очень легко упустить из виду, но он имеет большое значение, в общем, мне это не нравится. Также требуется знание работы языка (powershell не является статически типизированным, и я не хочу, чтобы читатель знал, что является правдивым или нет). Это может звучать глупо, но PowerShell не мой основной язык, ни мои коллеги. Читаемость является ключевым фактором для меня.

1 Ответ

0 голосов
/ 03 сентября 2018

ТЛ; др

Чтобы сравнить значение с $null с -eq или -ne, всегда сделайте $null LHS :

$null -eq $psCustomObject.x  # NOT $psCustomObject.x -eq $null
  • Порядок операндов имеет значение, потому что операторы сравнения в PowerShell действуют как фильтры с значениями массива значения LHS.

  • Кроме того, даже при сравнении с чем-то отличным от $null порядок операндов может иметь значение из-за неявных преобразований типов.


Операторы сравнения PowerShell , такие как -eq, по конструкции работают по-разному с значениями массива LHS и, следовательно, какой операнд находится там, где имеет значение даже для обычно коммутативных операторов
-eq и -ne.

  • С a скаляр LHS (одно значение), оператор сравнения возвращает Boolean ($True или $False, который указывает на результат сравнения.

    • Однако даже при размещении операндов скаляров может иметь значение , как отмечает Джефф Цейтлин , а именно с операндами различных типов : обычно RHS операнд приводится к типу данных LHS перед сравнением ; Например, ' 2 ' -eq 2 выполняет сравнение строк (приводит целое число 2 к строке '2') и, следовательно, возвращает $False, тогда как 2 -eq ' 2 ' выполняет сравнение integer (преобразует строку ' 2 ' к [int]) и поэтому возвращает $True.
  • С массивом -значным LHS (значения LHS, являющимся коллекцией), оператор сравнения возвращает массив ([object[]]), поскольку он действует как фильтр : оператор применяется к элементам входного массива индивидуально , и возвращается подмассив тех элементов, для которых возвращена операция $True.

Обратите внимание, что в Windows PowerShell v5.1 / PowerShell Core 6.1.0 PowerShell поддерживает операнды со значениями массива только как операнд LHS ; Операнды RHS должны быть скалярами или приводиться к одному. [1]


Следовательно, в вашем примере $null -eq $psCustomObject.x и $psCustomObject.x -eq $null являются не взаимозаменяемыми и тестируют различные условия :

# Is the RHS $null?
# Whether the concrete RHS value is then a scalar or an array doesn't matter.
$null -eq $psCustomObject.x

# * If $psCustomObject.x is a scalar: is that scalar $null?
# * If $psCustomObject.x is an ARRAY: 
#   RETURN THE SUB-ARRAY OF ELEMENTS THAT ARE $null
$psCustomObject.x -eq $null

При использовании в логическом контексте , например, в операторе if, массивы , например, возвращаемые с LHS со значением массива, оцениваются следующим образом : Кончик шляпы PetSerAl за помощь.

  • пустой массив или 1-элементный массив, содержащий пустой массив , оценивается как $False.
  • 1-элементный массив, содержащий скаляр оценивает (подразумеваемое) логическое значение этого скаляра, например, [bool] @(0) фактически совпадает с [bool] 0, то есть $False.
  • A 2 + -элементный массив или 1-элементный массив, содержащий непустой массив is всегда $True, независимо от его элементов 'значения (например,
    [bool] ($False, $False) и [bool] (, (, $False)) являются $True.

Примечание: термин массив используется свободно выше. Строго говоря, вышесказанное относится к экземплярам любого типа, которые реализуют интерфейс [System.Collections.IList] - см. исходный код .
В дополнение к массивам, это включает типы, такие как [System.Collections.ArrayList] и [System.Collections.Generic.List[<type>]].


Пример того, когда два сравнения оцениваются по-разному в логическом контексте:

Примечание:

  • Этот пример несколько надуманный - сообщите нам, если есть лучшие.
    Более простые примеры могут быть предоставлены с оператором -ne.

  • Я не смог придумать пример для конкретного поведения, которое вы описываете, где $null -eq $psCustomObject.x возвращает $True, а $psCustomObject.x -eq $null - нет. Если это действительно то, что вы видели, пожалуйста, сообщите нам конкретное значение .x.

# Construct a custom object with an array-valued .x property that
# contains at least 2 $null values.
$psCustomObject = [pscustomobject] @{ x = @(1, $null, 2, $null) }

# $False, as expected: the value of .x is an array, and therefore not $null
[bool] ($null -eq $psCustomObject.x) 

# !! $True, because because 2 elements in the input array (.x)
# !! are $null, so a 2-element array - ($null, $null) - is returned, which in a
# !! Boolean context is always $True.
[bool] ($psCustomObject.x -eq $null) 

[1] В документах -replace сгруппирован с операторами сравнения, и технически его RHS является массивом, но элементами этого массива являются по своей природе скалярные операнды: регулярное выражение для сравнения и строка замены.

...