Другое событие NullPointerException
возникает, когда объявляется массив объектов, а затем сразу же пытается разыменовать его внутри.
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Этот конкретный NPE можно избежать, если порядок сравнения отменяется ; а именно, использовать .equals
для гарантированного непустого объекта.
Все элементы внутри массива инициализируются их общим начальным значением ; для любого типа массива объектов, это означает, что все элементы null
.
Вы должны инициализировать элементы в массиве перед доступом или разыменованием их.
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Параметры при вызове функций в PowerShell (все версии) разделены пробелами, а не запятыми. Кроме того, скобки полностью не нужны и вызовут ошибку синтаксического анализа в powershell 2.0 (или более поздней), если Set-StrictMode
активен. Параметризованные аргументы используются только в .NET-методах.
function foo($a, $b, $c) {
"a: $a; b: $b; c: $c"
}
ps> foo 1 2 3
a: 1; b: 2; c: 3
Я не знаю, что вы делаете с функцией, но посмотрите на использование ключевого слова «param». Это намного более мощно для передачи параметров в функцию и делает ее более удобной для пользователя. Ниже приведена ссылка на слишком сложную статью от Microsoft об этом. Это не так сложно, как в статье. Использование параметра
Также приведен пример из потока на этом сайте:
Проверьте это.
Если вы попытаетесь:
PS > Test("ABC", "GHI") ("DEF")
, вы получите:
$arg1 value: ABC GHI
$arg2 value: DEF
. Если вы попытаетесь:
PS > $var = "C"
PS > Test ("AB" + $var) "DEF"
вы получаете:
$arg1 value: ABC
$arg2 value: DEF
Теперь вы можете найти некоторую непосредственную полезность скобки - пространство не станет разделителем для следующего параметра - вместо этого у вас есть eval.
Если вы не знаете (или не заботитесь) о том, сколько аргументов вы перейдете к функции, вы также можете использовать очень простой подход:
Код:
function FunctionName()
{
Write-Host $args
}
Это будет печатать все аргументы. Например:
FunctionName a b c 1 2 3
Выход
a b c 1 2 3
Я считаю это особенно полезным при создании функций, которые используют внешние команды, которые могут иметь много разных (и необязательных) параметров, но полагаются на указанную команду для обеспечения обратной связи по синтаксическим ошибкам и т. д.
Вот еще один пример реального мира (создание функции для команды tracert, которую я ненавижу, чтобы помнить усеченное имя);
Код:
Function traceroute
{
Start-Process -FilePath "$env:systemroot\system32\tracert.exe" -ArgumentList $args -NoNewWindow
}
Поскольку это часто просматриваемый вопрос, я хочу упомянуть, что функция PowerShell должна использовать одобренные глаголы (Verb-Noun как имя функции). Также вы можете указать такие параметры, как параметр обязательный и положение параметра:
function Test-Script
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true, Position=0)]
[string]$arg1,
[Parameter(Mandatory=$true, Position=1)]
[string]$arg2
)
Write-Host "`$arg1 value: $arg1"
Write-Host "`$arg2 value: $arg2"
}
Чтобы передать параметр в вы можете либо использовать позицию:
Test-Script "Hello" "World"
Или вы укажите имя параметра:
Test-Script -arg1 "Hello" -arg2 "World"
Вы не используете круглые скобки, например вы делаете, когда вызываете функцию внутри C #.
Я бы рекомендовал always передавать имена параметров при использовании более одного параметра, так как это больше читаемый .
Вы также можете передавать параметры в функции.
function FunctionName()
{
Param ([string]$ParamName);
#Operations
}
Вы вызываете функции PowerShell без скобок и без использования запятой в качестве разделителя. Попробуйте использовать:
test "ABC" "DEF"
В PowerShell запятая (,) является оператором массива, например
$a = "one", "two", "three"
Она устанавливает $ a в массив с тремя значениями.
Function Test([string]$arg1, [string]$arg2)
{
Write-Host "`$arg1 value: $arg1"
Write-Host "`$arg2 value: $arg2"
}
Test("ABC") ("DEF")
Правильный ответ уже предоставлен, но этот вопрос кажется достаточно распространенным, чтобы гарантировать некоторые дополнительные детали для тех, кто хочет понять тонкости. Я бы добавил это как комментарий, но я хотел включить иллюстрацию - я потерял это из моей быстрой справочной диаграммы функций PowerShell. Это предполагает, что сигнатура функции f является f($a, $b, $c)
:
[/g4]
Таким образом, можно вызвать функцию с пространственным разделением positional параметры или независимые от заказа параметры с именем . Другие подводные камни показывают, что вам нужно знать запятые, круглые скобки, и пустое пространство.
Для дальнейшего чтения см. Мою статью Вниз по кроличьей дыре: исследование в Трубопроводы, функции и параметры PowerShell , опубликованные только на Simple-Talk.com. В статье также содержится ссылка на краткую справочную / настенную диаграмму.
Function Test([string]$arg1, [string]$arg2)
{
Write-Host "`$arg1 value: $arg1"
Write-Host "`$arg2 value: $arg2"
}
Test "ABC" "DEF"
I утверждает следующее ранее:
Общая проблема заключается в использовании сингулярной формы $arg
, что неверно. Он должен всегда быть множественным как $args
.
Проблема не в этом. Фактически, $arg
может быть чем угодно. Проблема заключалась в использовании запятой и скобками. Я запускаю следующий код, который работал, и результат следует:
Код:
Function Test([string]$var1, [string]$var2)
{
Write-Host "`$var1 value: $var1"
Write-Host "`$var2 value: $var2"
}
Тест «ABC» «DEF»
Выход:
Значение $ var1: значение ABC $ var2: DEF
Function Test {
Param([string]$arg1, [string]$arg2)
Write-Host $arg1
Write-Host $arg2
}
Это правильное объявление параметров https://technet.microsoft.com/en-us/library/dd347600.aspx
И это действительно работает
Некоторые хорошие ответы здесь, но я хотел указать еще пару вещей. Функциональные параметры на самом деле являются местом, где сияет PowerShell. Например, вы можете иметь либо именованные, либо позиционные параметры в таких расширенных функциях:
function Get-Something
{
Param
(
[Parameter(Mandatory=$true, Position=0)]
[string] $Name,
[Parameter(Mandatory=$true, Position=1)]
[int] $Id
)
}
Тогда вы можете либо вызвать его, указав имя параметра, либо просто использовать позиционные параметры, так как вы явно определили их. Таким образом, любой из них будет работать:
Get-Something -Id 34 -Name "Blah"
Get-Something "Blah" 34
Первый пример работает, хотя имя предоставляется вторым, потому что мы явно использовали имя параметра. Второй пример работает на основе позиции, поэтому Name должно быть первым. Когда это возможно, я всегда пытаюсь определить позиции, так что доступны обе опции.
PowerShell также имеет возможность определять наборы параметров. Он использует это вместо перегрузки метода и снова весьма полезен:
function Get-Something
{
[CmdletBinding(DefaultParameterSetName='Name')]
Param
(
[Parameter(Mandatory=$true, Position=0, ParameterSetName='Name')]
[string] $Name,
[Parameter(Mandatory=$true, Position=0, ParameterSetName='Id')]
[int] $Id
)
}
Теперь функция либо примет имя, либо идентификатор, но не то, и другое. Вы можете использовать их позиционно или по имени. Поскольку они представляют собой другой тип, PowerShell выяснит это. Таким образом, все это будет работать
Get-Something "some name"
Get-Something 23
Get-Something -Name "some name"
Get-Something -Id 23
. Вы также можете назначить дополнительные параметры для различных наборов параметров. (Очевидно, это был довольно простой пример). Внутри функции вы можете определить, какой набор параметров использовался с свойством $ PsCmdlet.ParameterSetName. Например:
if($PsCmdlet.ParameterSetName -eq "Name")
{
Write-Host "Doing something with name here"
}
Затем в соответствующей заметке есть также проверка параметров в PowerShell. Это одна из моих любимых функций PowerShell, и она делает код внутри ваших функций очень чистым. Существуют многочисленные проверки, которые вы можете использовать. Пара примеров -
function Get-Something
{
Param
(
[Parameter(Mandatory=$true, Position=0)]
[ValidatePattern('^Some.*')]
[string] $Name,
[Parameter(Mandatory=$true, Position=1)]
[ValidateRange(10,100)]
[int] $Id
)
}
. В первом примере ValidatePattern принимает регулярное выражение, которое гарантирует, что предоставленный параметр соответствует ожидаемому. Если это не так, возникает интуитивное исключение, в котором вы точно указываете, что не так. Таким образом, в этом примере «что-то» будет работать нормально, но «лето» не пройдет проверку.
ValidateRange гарантирует, что значение параметра находится между диапазоном, который вы ожидаете от целого. Таким образом, 10 или 99 будут работать, но 101 сделает исключение.
Еще один полезный вариант - ValidateSet, который позволяет явно определить массив допустимых значений. Если что-то еще введено, будет выбрано исключение. Есть и другие, но, вероятно, наиболее полезным является ValidateScript. Для этого требуется блок сценария, который должен оцениваться до $ true, поэтому небо - это предел. Например:
function Get-Something
{
Param
(
[Parameter(Mandatory=$true, Position=0)]
[ValidateScript({ Test-Path $_ -PathType 'Leaf' })]
[ValidateScript({ (Get-Item $_ | select -Expand Extension) -eq ".csv" })]
[string] $Path
)
}
В этом примере мы уверены не только в том, что $ Path существует, но и в том, что это файл (в отличие от каталога) и имеет расширение .csv. ($ _ относится к параметру, когда внутри вашего скриптового блока.) Вы также можете передавать гораздо большие многострочные блоки сценариев, если требуется этот уровень, или использовать несколько сценариев, подобных мне. Это чрезвычайно полезно и обеспечивает отличные чистые функции и интуитивные исключения.
My_Function -NamedParamater "ParamValue"
. Это шаблон, который требует больше кода сценария PS для удобочитаемости.
– Mister_Tom
22 November 2017 в 20:46
(1,2,3)
функции эффективно рассматривается как массив; один аргумент. Если вы хотите использовать аргументы стиля метода OO, используйте модули:$m = new-module -ascustomobject { function Add($x,$y) { $x + $y } }; $m.Add(1,1)
– x0n 19 March 2014 в 15:18