Как вы можете проверить, имеет ли объект определенное свойство?

93

Как вы можете проверить, имеет ли объект определенное свойство?

Цените, что я могу ...

$members = Get-Member -InputObject $myobject 

а затем foreachчерез $members, но есть ли функция для проверки наличия у объекта определенного свойства?

Дополнительная информация: проблема в том, что я импортирую CSV-файл двух разных типов: один с двумя столбцами, а другой - с тремя. Я не мог заставить чек работать с «Свойством», только с «NoteProperty» ... какая бы разница

if ( ($member.MemberType -eq "NoteProperty" ) -and ($member.Name -eq $propertyName) ) 
SteveC
источник
6
($object.property -ne $null)?
arco444
2
Имеет ли значение, существует ли собственность, но имеет ли она $nullценность?
Мэтт
1
@ arco444 nope - для успешного выполнения этого требуется, чтобы свойство существовало. - Если у вас есть динамические данные (например, из веб-запроса), в которых некоторые строки даже не указывают это свойство, эта проверка завершится ошибкой. :(
BrainSlugs83

Ответы:

104

Как это?

 [bool]($myObject.PSobject.Properties.name -match "myPropertyNameToTest")
CB.
источник
16
Этот ответ работает только для PowerShell v3 или выше. Следующее должно работать даже с PowerShell v2 и выше: [bool] ($ file.psobject.Properties | where {$ _. Name -eq "myPropertyNameToTest"})
Патрик
33
$myObject.PSobject.Properties.Name -contains "myPropertyNameToTest"лучше. Не нужно беспокоиться о возможном сопоставлении с образцом, и вам также не нужно будет приводить к логическому типу.
Bacon Bits
2
Что, если у объекта есть свойство, ThisisMyPropertyи вы хотите его проверить MyProperty? Все решения в этом ответе приведут к ложному срабатыванию.
Золтан Тамаши
3
@KolobCanyon Это не будет работать в строгом режиме.
user2864740 05
1
Этот код даст ложное срабатывание, если, например, вы при тестировании на «Счетчик» и объект имели свойство под названием «ThingCount».
dan-gph
72

Ты можешь использовать Get-Member

if(Get-Member -inputobject $var -name "Property" -Membertype Properties){
#Property exists
}
Павел
источник
12
Лучший ответ ИМХО. Это работает с объектами .NET, у которых нет члена PSobject. Мы также можем удалить параметр -Membertype, если нас не волнует, какой тип члена содержит объект - только имя члена. Очень полезно с объектами Invoke-RestMethod или ConvertFrom-Json!
Mister_Tom
2
Короткий синтаксис без проверки типа:, if($var | Get-Member Property){ }даже короче, но менее if($var | gm Property){ }
читабелен
На мой взгляд, это лучший ответ.
Киран Хегде
25

Это сжато и доступно для чтения:

"MyProperty" -in $MyObject.PSobject.Properties.Name

Мы можем поместить это в функцию:

function HasProperty($object, $propertyName)
{
    $propertyName -in $object.PSobject.Properties.Name
}
дан-гф
источник
Мне нравится этот ответ, но, похоже, он не работает в некоторых случаях, когда отвечает ответ CB.
edwin
Или, где "succinct" = "ненужный мусор, введенный через строгий режим без хорошего варианта использования запасного варианта" (т. ?.Е. Без эквивалента): | Это также не удастся для некоторых вариантов $MyObject, в частности $ null. Но этого не было с нулевой цепочкой вне строгого режима.
user2864740 06
5

Я использовал следующее, которое возвращает значение свойства, поскольку к нему можно получить доступ$thing.$prop , если «свойство» должно существовать, а не генерировать случайное исключение. Если свойство «не существует» (или имеет нулевое значение), то $nullвозвращается: этот подход работает в / полезен для строгого режима , потому что, ну, Gonna Catch 'em All.

Я считаю этот подход полезным, потому что он позволяет обрабатывать пользовательские объекты PS, обычные объекты .NET, PS HashTables и коллекции .NET, такие как Dictionary, как «утиный эквивалент» , который, как я считаю, довольно хорошо подходит для PowerShell.

Конечно, это не соответствует строгому определению термина «имеет свойство» ... которым этот вопрос может быть явно ограничен. Если принять более широкое определение «свойства», предложенное здесь, метод можно тривиально изменить, чтобы он возвращал логическое значение.

Function Get-PropOrNull {
    param($thing, [string]$prop)
    Try {
        $thing.$prop
    } Catch {
    }
}

Примеры:

Get-PropOrNull (Get-Date) "Date"                   # => Monday, February 05, 2018 12:00:00 AM
Get-PropOrNull (Get-Date) "flub"                   # => $null
Get-PropOrNull (@{x="HashTable"}) "x"              # => "HashTable"
Get-PropOrNull ([PSCustomObject]@{x="Custom"}) "x" # => "Custom"
$oldDict = New-Object "System.Collections.HashTable"
$oldDict["x"] = "OldDict"
Get-PropOrNull $d "x"                              # => "OldDict"

И такое поведение может не [всегда] быть желательным ... т.е. невозможно различить x.Countи x["Count"].

user2864740
источник
3

Однако для меня MyProperty" -in $MyObject.PSobject.Properties.Nameне сработало

$MyObject.PSobject.Properties.Name.Contains("MyProperty")

работает

sebke CCU
источник
2

Если вы используете StrictMode и объект psobject может быть пустым, это выдаст вам ошибку.

Для всех целей это подойдет:

    if (($json.PSobject.Properties | Foreach {$_.Name}) -contains $variable)
Адам Ковач
источник
1

Реально похоже на проверку javascript:

foreach($member in $members)
{
    if($member.PropertyName)
    {
        Write $member.PropertyName
    }
    else
    {
        Write "Nope!"
    }
}
YtramX
источник
1
Это может не сработать, если свойство действительно имеет значение $ null.
Tola Odejayi
8
Это не удастся, если PowerShell находится в строгом режиме.
Ян Кемп
@IanKemp Что такое строгий режим? Нравится политика исполнения?
Каньон Колоб
1
@KolobCanyon docs.microsoft.com/en-za/powershell/module/… - по сути, это PS-эквивалент JavaScript use strict.
Ян Кемп
1
Это также не будет работать, если свойство существует и установлено в $ false.
1

Просто чтобы уточнить, учитывая следующий объект

$Object

Со следующими свойствами

type        : message
user        : john.doe@company.com
text        : 
ts          : 11/21/2016 8:59:30 PM

Следующее верно

$Object.text -eq $NULL
$Object.NotPresent -eq $NULL

-not $Object.text
-not $Object.NotPresent

Таким образом, более ранние ответы, в которых явно проверяется свойство по имени, являются наиболее правильным способом проверить, что это свойство отсутствует.

Джон Мелло
источник
1

Просто проверьте против нуля.

($myObject.MyProperty -ne $null)

Если вы не установили PowerShell на StrictMode , это работает, даже если свойство не существует:

$obj = New-Object PSObject;                                                   
Add-Member -InputObject $obj -MemberType NoteProperty -Name Foo -Value "Bar";
$obj.Foo; # Bar                                                                  
($obj.MyProperty -ne $null);  # False, no exception
Шон Латтин
источник
2
Насколько я понимаю, это работает, если свойство существует и равно $ null, но не, если свойство не существует - попытка доступа к нему для выполнения проверки на null вызывает исключение.
Питер
@Peter Можете ли вы предоставить пример проверки на null, вызывающей исключение, когда свойство не существует. Я добавил пример, в котором свойство не существует и нет исключений.
Shaun Luttin
2
Запустите это: Set-Strictmode -version Latest;$obj = ConvertFrom-Json -InputObject '{"name":"test", "version":"1.1.0"}';If($obj.StartDate -ne $null){Write-Verbose -Message $obj.startDate -Verbose}и вы получите сообщение об ошибке. Свойство StartDate не может быть найдено для этого объекта. Однако мне нужно уточнить свой комментарий - вы не получите его, если не установлен Strictmode. У меня он всегда был установлен, поэтому никогда не осознавал, пока не протестировал его! Тем не менее, я думаю, что большинство людей используют (или должны использовать) Set-Strictmode.
Питер
2
Наверное, лучше всего, если вы уточните свой ответ, и я удалю свой голос против? Каждый чему-то научился, вот в чем суть :-)
Питер
0

У меня получилась следующая функция ...

function HasNoteProperty(
    [object]$testObject,
    [string]$propertyName
)
{
    $members = Get-Member -InputObject $testObject 
    if ($members -ne $null -and $members.count -gt 0) 
    { 
        foreach($member in $members) 
        { 
            if ( ($member.MemberType -eq "NoteProperty" )  -and `
                 ($member.Name       -eq $propertyName) ) 
            { 
                return $true 
            } 
        } 
        return $false 
    } 
    else 
    { 
        return $false; 
    }
}
SteveC
источник
0

Недавно я переключился на установку strict-mode -version 2.0, и мои нулевые тесты не прошли.

Я добавил функцию:

#use in strict mode to validate property exists before using
function exists {
  param($obj,$prop)
  try {
    if ($null -ne $obj[$prop]) {return $true}
    return $false
  } catch {
    return $false
  }
  return $false
}

Теперь я кодирую

if (exists $run main) { ...

скорее, чем

if ($run.main -ne $null) { ...

и мы в пути. Кажется, работает с объектами и хэш-таблицами

В качестве непреднамеренного преимущества меньше набора текста.

Стив Причард
источник
Для нулевого или пустого я всегда использовал: IF ([string] :: IsNullOrEmpty ($ userID)) {write-host "Null or empty"}
0

Я просто хотел добавить к обсуждению, потому что я просто часами отлаживал код, который работал где-то еще.

Ответ CB. хорошо работает для сопоставления переменной с именами свойств (в виде строк). Проблема началась, когда переменная совпала с частью имени свойства.

if([bool]($allFiles.PSobject.Properties.name -match $_.Name) -ne $true){

Позже я использовал его для ссылки на свойство объекта, но поскольку оно соответствовало только части другого свойства, поэтому фактического свойства с таким точным именем не существовало, операция вернула значение «null».

Только позже я использовал решение, предложенное dan-gph , оно очень аккуратное:

if([bool]($_.Name -in $allFiles.PSobject.Properties.Name) -ne $true){

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

Байрон
источник
-1

Я только начал использовать PowerShell с PowerShell Core 6.0 (бета), и следующее просто работает:

if ($members.NoteProperty) {
   # NoteProperty exist
}

или

if (-not $members.NoteProperty) {
   # NoteProperty does not exist
}
hshib
источник
1
Не со строгим режимом
Каспер Леон Нильсен
-1

Вы можете проверить:

($Member.PropertyNames -contains "Name") это проверит свойство Named

Том Стрин
источник
-1

Для определения того, какой из объектов в массиве имеет свойство

$HasProperty = $ArrayOfObjects | Where-Object {$_.MyProperty}
пробковый
источник
Не работает в StrictMode, когда свойство не существует.
user2864740