Почему я не могу вызвать метод Contains из моего массива? - PullRequest
6 голосов
/ 28 мая 2010

Arrrg! Я сталкиваюсь с тем, что мне кажется глупым, с простым сценарием, который я пишу на powershell. Я вызываю команду sql, которая вызывает хранимый процесс, с результатами я помещаю его в массив. Результаты выглядят примерно так:

Status                                       ProcessStartTime                            ProcessEndTime                             
------                                       ----------------                            --------------                             
Expired                                      May 22 2010  8:31PM                         May 22 2010  8:32PM

Я пытаюсь сделать if($s.Contains("Expired")), отчет не выполнен. Просто...? :( Проблема, с которой я сталкиваюсь, похоже, что метод Contains не загружается, поскольку я получаю сообщение об ошибке, подобное этому:

Ошибка вызова метода, поскольку [System.Object []] не содержит метод с именем «Contains». В строке: 1 символ: 12 + $ s.Contains <<<< ("Просрочено") + CategoryInfo: InvalidOperation: (Содержит: String) [], RuntimeException + FullyQualifiedErrorId: MethodNotFound </em>

Итак, что я могу сделать, чтобы PowerShell не развернул его в строку? Фактический скрипт ps ниже -

$s = @(Invoke-Sqlcmd -Query "USE DB
       GO
       exec Monitor_TEST_ps 'EXPORT_RUN',NULL,20" `
       -ServerInstance testdb002\testdb_002
      )

if ($s.Contains("Expired"))   
{
    Write-Host "Expired found, FAIL."
}
else 
{
    Write-Host "Not found, OK." 
}

Ответы [ 2 ]

7 голосов
/ 29 мая 2010

Проще говоря, $ s - это массив .NET (вы используете @() гарантирует это), и вы пытаетесь вызвать метод (Contains), которого нет в этом типе .NET.

Самый простой способ решения вашей проблемы - использовать оператор PowerShell -contains, который имеет преимущества работы с массивами напрямую и сравнения без учета регистра, например ::1005*

if ($s -contains 'expired') { ... }
5 голосов
/ 28 мая 2010

Причина, по которой вы видите метод Get-Members, заключается в том, что powershell пытается помочь и разворачивает коллекцию. Если у вас есть массив с несколькими типами элементов, он показывает вам элементы для каждого типа (например, если вы 'ls' (Get-ChildItem) и в каталоге, в котором вы находитесь, есть FileInfos и DirectoryInfos, и вы передаете ls | gm , он покажет вам членов FileInfos, а также другую группу членов DirectoryInfos):

(7) C:\ -» ls


    Directory: C:\


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         5/28/2010   8:19 AM            .hg
d----         5/13/2010   3:37 PM            Build
…
-a---         4/22/2010  11:21 AM       2603 TODO.org


(8) C:\ -» ls | gm


   TypeName: System.IO.DirectoryInfo

Name                      MemberType     Definition
----                      ----------     ----------
Mode                      CodeProperty   System.String Mode{get=Mode;}
Create                    Method         System.Void Create(System.Security.AccessControl.Direct...
…

   TypeName: System.IO.FileInfo

Name                      MemberType     Definition
----                      ----------     ----------
Mode                      CodeProperty   System.String Mode{get=Mode;}
AppendText                Method         System.IO.StreamWriter AppendText()
…

Что я обычно делаю, чтобы убедиться, что я не смотрю на развернутых участников, сначала попробуйте «$ s.GetType (). Name», чтобы увидеть, с чем я имею дело. В вашем случае это явно и массив, так как вы инициализировали его как «$ s = @ (Invo» (@ = это массив.)

Чтобы узнать, содержит ли массив элемент, вы можете использовать оператор -contains:

(9) C:\ -» @(1,2,3) -contains 1
True

Я думаю, у вас есть массив строк, поэтому вы можете использовать строковый литерал, например:

(10) C:\ -» @("Stuff","you've","got","might have","Expired") -contains "Expired"
True

Но если истекший срок не является точным соответствием (вы искали элемент, содержащий истекший срок действия, например «Соединение с истекшим сроком действия 01.01.2010»), вам нужно найти совпадения и проверить количество, я думаю:

(23) C:\ -» @("Stuff","you've","got","might have","Connection Expired 1/1/2010") -contains "Expired"
False
(24) C:\ -» @("Stuff","you've","got","might have","Connection Expired 1/1/2010") | ?{$_.Contains("Expired")}
Connection Expired 1/1/2010
(33) C:\ -» $xs = @("Stuff","you've","got","might have","Connection Expired 1/1/2010") | ?{$_.Contains("Expired")}
(34) C:\ -» $xs.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object


(35) C:\ -» $xs
Connection Expired 1/1/2010

В этом случае есть только одно совпадение, поэтому powershell развернул его до строки. Придурок. Однако, если найдено более 1 совпадений:

(36) C:\ -» $xs = @("Stuff","you've","got","might Expired  have","Connection Expired 1/1/2010") | ?{$_.Contains("Expired")}
(37) C:\ -» $xs.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array


(38) C:\ -» $xs
might Expired  have
Connection Expired 1/1/2010

Теперь это массив.

К счастью, и строка, и массив имеют свойство длины:

(39) C:\ -» $xs.Length
2
(40) C:\ -» "Bob".Length
3

Таким образом, вы можете проверить длину ваших результатов, которые содержат «Истек», чтобы увидеть, есть ли какие-либо просроченные:

(41) C:\ -» $xs = @("Stuff","you've","got","might Expired  have","Connection Expired 1/1/2010") | ?{$_.Contains("Expired")} 
(42) C:\ -» if ($xs.Length -gt 0) { Write-Host "Whoas, stuff's expired, dog." }
Whoas, shit's expired, dog.

(может быть, у кого-то есть лучший способ проверить, содержит ли коллекция элемент, удовлетворяющий некоторому предикату (например, LINQ)?)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...