PowerShellでのヌル合体


115

PowerShellにnullの合体演算子はありますか?

PowerShellでこれらのc#コマンドを実行できるようにしたいと思います。

var s = myval ?? "new value";
var x = myval == null ? "" : otherval;

回答:


133

Powershell 7以降

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式形式を使用してください。


6
合体演算子に対応する唯一の真の条件は、ifステートメントを使用することです。問題は、他のアプローチでは、短絡ではなくすべてのオペランドが評価されることです。「?? $ myval SomeReallyExpenisveFunction()」は、$ myvalがnullでない場合でも関数を呼び出します。スクリプトブロックを使用すると評価が遅れる可能性があると思いますが、スクリプトブロックはクロージャーではなく、物事が不規則になり始めることに注意してください。
Thomas S. Trias

ストリクトモードでは機能しません-スローしThe variable '$myval' cannot be retrieved because it has not been set.ます。
BrainSlugs83

1
@ BrainSlugs83 strictモードで表示されるエラーは、提示されたnullの結合オプションとは無関係です。変数が最初に定義されていることを確認するのは標準のPowershellです。$myval = $nullテストを行う前に設定すると、エラーは解消されます。
StephenD

1
警告、Powershellの癖、nullは常に比較し(ぎこちなく)、nullを最初に配置する必要があります$null -ne $a
dudeNumber4

90

PowerShell 7以降

PowerShell 7は多くの新機能を導入し、.NET Frameworkから.NET Coreに移行します。2020年半ばの時点で、.NET Coreに依存しているため、PowerShellのレガシーバージョンは完全に置き換えられていませんが、Microsoftは、コアファミリーがレガシーフレームワークファミリーを最終的に置き換えることを意図していることを示しています。これを読んだ時点で、互換性のあるバージョンのPowerShellがシステムにプリインストールされている場合があります。そうでない場合は、https://github.com/powershell/powershellを参照してください

ドキュメントによれば PowerShell 7.0では、次の演算子が標準でサポートされています。

  1. ヌル合体??
  2. ヌル結合の割り当て??=
  3. 三元... ? ... : ...

これらは、nullの合体で期待されるとおりに機能します。

$x = $a ?? $b ?? $c ?? 'default value'
$y ??= 'default value'

3項演算子が導入されたため、次のことが可能になりましたが、nullの合体演算子を追加した場合は不要です。

$x = $a -eq $null ? $b : $a

場合7.0のように、次のようにも利用可能であるPSNullConditionalOperatorsオプション機能がされている有効ドキュメント(で説明したように、12)。

  1. メンバーのヌル条件付きメンバーアクセス: ?.
  2. 配列などのnull条件付きメンバーアクセス: ?[]

これらにはいくつかの注意点があります:

  1. これらは実験的なものであるため、変更される可能性があります。これを読んだ時点では、実験的であるとは見なされておらず、警告のリストが変更されている可能性があります。
  2. ${}変数名では疑問符を使用できるため、変数の後に実験演算子のいずれかが続く場合は、変数を囲む必要があります。機能が実験的ステータスを卒業する場合またはその場合、これが当てはまるかどうかは不明です(問題#11379を参照)。たとえば、${x}?.Test()はnew演算子を使用します$x?.Test()Test()、という変数で実行されます$x?
  3. ?(TypeScriptを使用している場合に予想されるような演算子はありません。以下は機能しません:$x.Test?()

PowerShell 6およびそれ以前

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

説明

この説明は、匿名ユーザーからの編集提案に基づいています。ありがとうございます。

操作の順序に基づいて、これは次の順序で機能します。

  1. ,オペレータは、試験されるべき値の配列を作成します。
  2. -neこの場合、ヌル-指定された値と一致する配列から任意の項目アウトオペレータフィルタ。結果は、手順1で作成した配列と同じ順序のnull以外の値の配列です。
  3. [0] フィルターされた配列の最初の要素を選択するために使用されます。

それを単純化する:

  1. 可能な値の配列を優先順に作成します
  2. 配列からすべてのnull値を除外する
  3. 結果の配列から最初の項目を取得します

注意事項

C#のnullの合体演算子とは異なり、最初の手順は配列の作成であるため、考えられるすべての式が評価されます。


私はあなたの答えの修正版を使用して終了鉱山で、私は例外をスローせず、COALESCE内のすべてのインスタンスがnullであることを可能にするために必要ので、。それを行う非常に素晴らしい方法ですが、私は多くを学びました。:)
ジョニースコブダル

この方法は短絡を防ぎます。これを確認function DidItRun($a) { Write-Host "It ran with $a"; return $a }する((DidItRun $null), (DidItRun 'alpha'), 1 -ne $null)[0]には、定義して実行します。
jpmc26 2017

@ jpmc26はい、それは仕様です。
Zenexer 2017

合体関数を定義しようとすると、短絡がなくなる可能性がありますね。
クリスFキャロル

8
Ahhhh PowerShellの演算子の優先順位は私を殺します!コンマ演算子の,優先順位が非常に高いことをいつも忘れています。これがどのように機能するかについて混乱している人にとって($null, 'alpha', 1 -ne $null)[0]は、と同じ(($null, 'alpha', 1) -ne $null)[0]です。実際、優先順位の高い2つの「ダッシュ」演算子は-split、and -join(および単項ダッシュ?、つまり-4or -'56')のみです。
プルート

15

これは質問の前半に対する答えの半分に過ぎないので、もしそうであれば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)-> ""「便利ですが、残念な副作用」のようです:(
user2864740


9

Powershell Community Extensions Moduleをインストールすると、以下を使用できます。

?? Invoke-NullCoalescingのエイリアスです。

$s = ?? {$myval}  {"New Value"}

?:Invoke-Ternaryのエイリアスです。

$x = ?: {$myval -eq $null} {""} {$otherval}

実際、それはPowerShellコマンドではありません。pscxでそれらを取得しました:?:-> Invoke-
Ternary

...実際のコードと結果がありません。;)Get-Command -Module pscx -CommandType alias | ここで、{$ _。Name -match '\ ?.' } | foreach {"{0}:{1}" -f $ _。Name、$ _。Definition}?::Invoke-Ternary ?? :Invoke-NullCoalescing
BartekB

おっと...あなたは完全に正しいです。モジュールをロードしていることさえ忘れてしまいがちです。
EBGreen、2012年



2
function coalesce {
   Param ([string[]]$list)
   #$default = $list[-1]
   $coalesced = ($list -ne $null)
   $coalesced[0]
 }
 function coalesce_empty { #COALESCE for empty_strings

   Param ([string[]]$list)
   #$default = $list[-1]
   $coalesced = (($list -ne $null) -ne '')[0]
   $coalesced[0]
 }

2

合体を使用する場合、空の文字列を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)

1

私が得ることができる最も近いものは: $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"

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.