回答:
Powershell 7の紹介ネイティブのnull結合、null条件付き代入、および三項演算子がます。
ヌル合体
$null ?? 100 # Result is 100
"Evaluated" ?? (Expensive-Operation "Not Evaluated") # Right side here is not evaluated
ヌル条件付き割り当て
$x = $null
$x ??= 100 # $x is now 100
$x ??= 200 # $x remains 100
三項演算子
$true ? "this value returned" : "this expression not evaluated"
$false ? "this expression not evaluated" : "this value returned"
Powershell Community Extensionsは不要です。標準のPowershell ifステートメントを式として使用できます。
variable = if (condition) { expr1 } else { expr2 }
だからあなたの最初のC#式の代わりに:
var s = myval ?? "new value";
次のいずれかになります(設定によって異なります)。
$s = if ($myval -eq $null) { "new value" } else { $myval }
$s = if ($myval -ne $null) { $myval } else { "new value" }
または、$ myvalに含まれる内容に応じて、次のように使用できます。
$s = if ($myval) { $myval } else { "new value" }
2番目のC#式は同様の方法でマップします。
var x = myval == null ? "" : otherval;
なる
$x = if ($myval -eq $null) { "" } else { $otherval }
公平を期すために、これらはそれほど素晴らしくはなく、C#フォームほど快適に使用できません。
読みやすくするために、非常に単純な関数でラップすることも検討してください。
function Coalesce($a, $b) { if ($a -ne $null) { $a } else { $b } }
$s = Coalesce $myval "new value"
またはおそらく、IfNull:
function IfNull($a, $b, $c) { if ($a -eq $null) { $b } else { $c } }
$s = IfNull $myval "new value" $myval
$x = IfNull $myval "" $otherval
ご覧のとおり、非常に単純な関数を使用すると、かなり自由な構文が得られます。
更新:ミックスで考慮する追加オプションの1つは、より一般的なIsTrue関数です。
function IfTrue($a, $b, $c) { if ($a) { $b } else { $c } }
$x = IfTrue ($myval -eq $null) "" $otherval
次に、Powershellが演算子のように見えるエイリアスを宣言する機能を組み合わせると、次のようになります。
New-Alias "??" Coalesce
$s = ?? $myval "new value"
New-Alias "?:" IfTrue
$ans = ?: ($q -eq "meaning of life") 42 $otherval
明らかに、これは必ずしもすべての人の好みになるわけではありませんが、あなたが探しているものかもしれません。
Thomasが指摘しているように、C#バージョンと上記のもう1つの微妙な違いは、C#が引数の短絡を実行することですが、関数/エイリアスを含むPowershellバージョンは常にすべての引数を評価します。これが問題になる場合は、if
式形式を使用してください。
The variable '$myval' cannot be retrieved because it has not been set.
ます。
$myval = $null
テストを行う前に設定すると、エラーは解消されます。
$null -ne $a
。
PowerShell 7は多くの新機能を導入し、.NET Frameworkから.NET Coreに移行します。2020年半ばの時点で、.NET Coreに依存しているため、PowerShellのレガシーバージョンは完全に置き換えられていませんが、Microsoftは、コアファミリーがレガシーフレームワークファミリーを最終的に置き換えることを意図していることを示しています。これを読んだ時点で、互換性のあるバージョンのPowerShellがシステムにプリインストールされている場合があります。そうでない場合は、https://github.com/powershell/powershellを参照してください。
ドキュメントによれば、 PowerShell 7.0では、次の演算子が標準でサポートされています。
これらは、nullの合体で期待されるとおりに機能します。
$x = $a ?? $b ?? $c ?? 'default value'
$y ??= 'default value'
3項演算子が導入されたため、次のことが可能になりましたが、nullの合体演算子を追加した場合は不要です。
$x = $a -eq $null ? $b : $a
場合7.0のように、次のようにも利用可能であるPSNullConditionalOperators
オプション機能がされている有効ドキュメント(で説明したように、1、2)。
?.
?[]
これらにはいくつかの注意点があります:
${}
変数名では疑問符を使用できるため、変数の後に実験演算子のいずれかが続く場合は、変数を囲む必要があります。機能が実験的ステータスを卒業する場合またはその場合、これが当てはまるかどうかは不明です(問題#11379を参照)。たとえば、${x}?.Test()
はnew演算子を使用します$x?.Test()
がTest()
、という変数で実行されます$x?
。?(
TypeScriptを使用している場合に予想されるような演算子はありません。以下は機能しません:$x.Test?()
7より前のバージョンのPowerShellには、実際のnull結合演算子、または少なくともそのような動作が可能な演算子があります。その演算子は-ne
:
# Format:
# ($a, $b, $c -ne $null)[0]
($null, 'alpha', 1 -ne $null)[0]
# Output:
alpha
これはすべての非nullアイテムの配列を作成するため、nullの合体演算子よりも多目的です。
$items = $null, 'alpha', 5, 0, '', @(), $null, $true, $false
$instances = $items -ne $null
[string]::Join(', ', ($instances | ForEach-Object -Process { $_.GetType() }))
# Result:
System.String, System.Int32, System.Int32, System.String, System.Object[],
System.Boolean, System.Boolean
-eq
同様に動作し、nullエントリをカウントするのに役立ちます。
($null, 'a', $null -eq $null).Length
# Result:
2
しかし、とにかく、C#の??
演算子をミラー化する典型的なケースを次に示します。
'Filename: {0}' -f ($filename, 'Unknown' -ne $null)[0] | Write-Output
この説明は、匿名ユーザーからの編集提案に基づいています。ありがとうございます。
操作の順序に基づいて、これは次の順序で機能します。
,
オペレータは、試験されるべき値の配列を作成します。-ne
この場合、ヌル-指定された値と一致する配列から任意の項目アウトオペレータフィルタ。結果は、手順1で作成した配列と同じ順序のnull以外の値の配列です。[0]
フィルターされた配列の最初の要素を選択するために使用されます。それを単純化する:
C#のnullの合体演算子とは異なり、最初の手順は配列の作成であるため、考えられるすべての式が評価されます。
function DidItRun($a) { Write-Host "It ran with $a"; return $a }
する((DidItRun $null), (DidItRun 'alpha'), 1 -ne $null)[0]
には、定義して実行します。
,
優先順位が非常に高いことをいつも忘れています。これがどのように機能するかについて混乱している人にとって($null, 'alpha', 1 -ne $null)[0]
は、と同じ(($null, 'alpha', 1) -ne $null)[0]
です。実際、優先順位の高い2つの「ダッシュ」演算子は-split
、and -join
(および単項ダッシュ?、つまり-4
or -'56'
)のみです。
これは質問の前半に対する答えの半分に過ぎないので、もしそうであれば4分の1の答えになりますが、使用するデフォルト値が実際には型のデフォルト値である場合、null融合演算子のはるかに簡単な代替手段があります:
string s = myval ?? "";
Powershellで次のように書くことができます:
([string]myval)
または
int d = myval ?? 0;
Powershellに変換します。
([int]myval)
存在しない可能性があり、存在する場合は不要な空白が含まれる可能性があるxml要素を処理するときに、これらの最初のものが有用であることがわかりました。
$name = ([string]$row.td[0]).Trim()
文字列へのキャストは、要素がnullになるのを防ぎ、Trim()
失敗するリスクを防ぎます。
([string]$null)
-> ""
「便利ですが、残念な副作用」のようです:(
Powershell Community Extensions Moduleをインストールすると、以下を使用できます。
?? Invoke-NullCoalescingのエイリアスです。
$s = ?? {$myval} {"New Value"}
?:Invoke-Ternaryのエイリアスです。
$x = ?: {$myval -eq $null} {""} {$otherval}
最後に、PowerShell 7にはNull Coalescing代入演算子が含まれています。
PS > $null ?? "a"
a
PS > "x" ?? "y"
x
PS > $x = $null
PS > $x ??= "abc"
PS > $x
abc
PS > $x ??= "xyz"
PS > $x
abc
合体を使用する場合、空の文字列をnullとして扱う必要があることもよくあります。私は結局、このための関数を作成しました。これは、単純なnull合体の合体にZenexerのソリューションを使用し、次にnullまたは空のチェックにKeith Hillのソリューションを使用し、それをフラグとして追加して、関数が両方を実行できるようにしました。
この関数の利点の1つは、すべての要素がnull(または空)であっても例外をスローせずに処理できることです。PowerShellが配列入力を処理する方法のおかげで、任意の多くの入力変数に使用することもできます。
function Coalesce([string[]] $StringsToLookThrough, [switch]$EmptyStringAsNull) {
if ($EmptyStringAsNull.IsPresent) {
return ($StringsToLookThrough | Where-Object { $_ } | Select-Object -first 1)
} else {
return (($StringsToLookThrough -ne $null) | Select-Object -first 1)
}
}
これにより、次のテスト結果が生成されます。
Null coallesce tests:
1 (w/o flag) - empty/null/'end' :
1 (with flag) - empty/null/'end' : end
2 (w/o flag) - empty/null :
2 (with flag) - empty/null :
3 (w/o flag) - empty/null/$false/'end' :
3 (with flag) - empty/null/$false/'end' : False
4 (w/o flag) - empty/null/"$false"/'end' :
4 (with flag) - empty/null/"$false"/'end' : False
5 (w/o flag) - empty/'false'/null/"$false"/'end':
5 (with flag) - empty/'false'/null/"$false"/'end': false
テストコード:
Write-Host "Null coalesce tests:"
Write-Host "1 (w/o flag) - empty/null/'end' :" (Coalesce '', $null, 'end')
Write-Host "1 (with flag) - empty/null/'end' :" (Coalesce '', $null, 'end' -EmptyStringAsNull)
Write-Host "2 (w/o flag) - empty/null :" (Coalesce('', $null))
Write-Host "2 (with flag) - empty/null :" (Coalesce('', $null) -EmptyStringAsNull)
Write-Host "3 (w/o flag) - empty/null/`$false/'end' :" (Coalesce '', $null, $false, 'end')
Write-Host "3 (with flag) - empty/null/`$false/'end' :" (Coalesce '', $null, $false, 'end' -EmptyStringAsNull)
Write-Host "4 (w/o flag) - empty/null/`"`$false`"/'end' :" (Coalesce '', $null, "$false", 'end')
Write-Host "4 (with flag) - empty/null/`"`$false`"/'end' :" (Coalesce '', $null, "$false", 'end' -EmptyStringAsNull)
Write-Host "5 (w/o flag) - empty/'false'/null/`"`$false`"/'end':" (Coalesce '', 'false', $null, "$false", 'end')
Write-Host "5 (with flag) - empty/'false'/null/`"`$false`"/'end':" (Coalesce '', 'false', $null, "$false", 'end' -EmptyStringAsNull)
私が得ることができる最も近いものは: $Val = $MyVal |?? "Default Value"
次のようにして、上記のnull合体演算子を実装しました。
function NullCoalesc {
param (
[Parameter(ValueFromPipeline=$true)]$Value,
[Parameter(Position=0)]$Default
)
if ($Value) { $Value } else { $Default }
}
Set-Alias -Name "??" -Value NullCoalesc
条件付き三項演算子は similaryな方法で実施することができます。
function ConditionalTernary {
param (
[Parameter(ValueFromPipeline=$true)]$Value,
[Parameter(Position=0)]$First,
[Parameter(Position=1)]$Second
)
if ($Value) { $First } else { $Second }
}
Set-Alias -Name "?:" -Value ConditionalTernary
そして次のように使用されます: $Val = $MyVal |?: $MyVal "Default Value"