มีตัวดำเนินการการรวมกันเป็นโมฆะใน powershell หรือไม่
ฉันต้องการที่จะสามารถทำคำสั่ง c # เหล่านี้ใน powershell:
var s = myval ?? "new value";
var x = myval == null ? "" : otherval;
มีตัวดำเนินการการรวมกันเป็นโมฆะใน powershell หรือไม่
ฉันต้องการที่จะสามารถทำคำสั่ง c # เหล่านี้ใน powershell:
var s = myval ?? "new value";
var x = myval == null ? "" : otherval;
คำตอบ:
Powershell 7 แนะนำการรวมศูนย์แบบเนทีฟการกำหนดเงื่อนไขว่างและตัวดำเนินการตามเงื่อนไขใน Powershell
Null Coalescing
$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
Ternary Operator
$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" }
และนิพจน์ 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
ดังที่คุณเห็นว่าฟังก์ชันที่เรียบง่ายสามารถให้อิสระในการใช้ไวยากรณ์ได้มาก
อัปเดต: ตัวเลือกพิเศษอย่างหนึ่งที่ควรพิจารณาในการผสมผสานคือฟังก์ชัน 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 # และเวอร์ชันข้างต้นคือ 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 ยังไม่ได้แทนที่ PowerShell เวอร์ชันเดิมอย่างสมบูรณ์เนื่องจากการพึ่งพา. NET Core แต่ Microsoft ได้ระบุว่าพวกเขาตั้งใจให้ตระกูล Core แทนที่ตระกูล Framework เดิมในที่สุด เมื่อคุณอ่านสิ่งนี้ PowerShell เวอร์ชันที่เข้ากันได้อาจติดตั้งมาล่วงหน้าในระบบของคุณ ถ้าไม่เห็นhttps://github.com/powershell/powershell
ตามเอกสารประกอบตัวดำเนินการต่อไปนี้ได้รับการสนับสนุนแบบสำเร็จรูปใน PowerShell 7.0:
??
??=
... ? ... : ...
สิ่งเหล่านี้ทำงานตามที่คุณคาดหวังสำหรับการรวมกันเป็นโมฆะ:
$x = $a ?? $b ?? $c ?? 'default value'
$y ??= 'default value'
เนื่องจากมีการแนะนำตัวดำเนินการ ternary จึงสามารถทำสิ่งต่อไปนี้ได้แม้ว่าจะไม่จำเป็นเนื่องจากการเพิ่มตัวดำเนินการเชื่อมต่อว่าง:
$x = $a -eq $null ? $b : $a
ในวันที่ 7.0 สิ่งต่อไปนี้จะพร้อมใช้งานหากเปิดใช้งานPSNullConditionalOperators
คุณสมบัติเสริมดังที่อธิบายไว้ในเอกสาร ( 1 , 2 ):
?.
?[]
สิ่งเหล่านี้มีข้อแม้บางประการ:
${}
if ตามด้วยตัวดำเนินการทดลองตัวใดตัวหนึ่งเนื่องจากอนุญาตให้ใช้เครื่องหมายคำถามในชื่อตัวแปร ยังไม่ชัดเจนว่าจะเป็นเช่นนี้หรือไม่หาก / เมื่อคุณลักษณะต่างๆออกจากสถานะทดลอง (ดูปัญหา # 11379 ) ยกตัวอย่างเช่นการ${x}?.Test()
ใช้ตัวดำเนินการใหม่ แต่$x?.Test()
ทำงานในชื่อตัวแปรTest()
$x?
?(
โอเปอเรเตอร์อย่างที่คุณคาดหวังหากคุณมาจาก TypeScript สิ่งต่อไปนี้ใช้ไม่ได้:$x.Test?()
PowerShell เวอร์ชันก่อนหน้า 7 มีตัวดำเนินการเชื่อมต่อว่างเปล่าจริงหรืออย่างน้อยก็เป็นตัวดำเนินการที่มีความสามารถในพฤติกรรมดังกล่าว ตัวดำเนินการนั้นคือ-ne
:
# Format:
# ($a, $b, $c -ne $null)[0]
($null, 'alpha', 1 -ne $null)[0]
# Output:
alpha
มันมีความหลากหลายมากกว่าตัวดำเนินการเชื่อมต่อแบบ 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, 'a', $null -eq $null).Length
# Result:
2
แต่อย่างไรก็ตามนี่เป็นกรณีทั่วไปในการสะท้อน??
ตัวดำเนินการของ C # :
'Filename: {0}' -f ($filename, 'Unknown' -ne $null)[0] | Write-Output
คำอธิบายนี้อ้างอิงจากคำแนะนำการแก้ไขจากผู้ใช้ที่ไม่ระบุชื่อ ขอบคุณไม่ว่าคุณจะเป็นใคร!
ตามลำดับของการดำเนินการสิ่งนี้ทำงานตามลำดับต่อไปนี้:
,
ดำเนินการสร้างอาร์เรย์ของค่าที่จะทดสอบ-ne
ดำเนินการจะกรองไอเท็มออกจากอาร์เรย์ที่ตรงกับค่าที่ระบุ - ในกรณีนี้คือ null ผลลัพธ์คืออาร์เรย์ของค่าที่ไม่ใช่ค่าว่างในลำดับเดียวกับอาร์เรย์ที่สร้างในขั้นตอนที่ 1[0]
ใช้เพื่อเลือกองค์ประกอบแรกของอาร์เรย์ที่กรองแล้วทำให้ง่ายขึ้น:
ซึ่งแตกต่างจากตัวดำเนินการการรวมค่าว่างของ C # ทุกนิพจน์ที่เป็นไปได้จะได้รับการประเมินเนื่องจากขั้นตอนแรกคือการสร้างอาร์เรย์
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]
. ในความเป็นจริงเพียงสองคนเท่านั้น "รีบ" ประกอบการที่มี precendence ที่สูงขึ้น-split
และ-join
(และประเอก? ie. -4
หรือ-'56'
)
นี่เป็นเพียงคำตอบครึ่งหนึ่งของคำถามครึ่งแรกดังนั้นคำตอบหนึ่งในสี่หากคุณต้องการ แต่มีทางเลือกอื่นที่ง่ายกว่ามากสำหรับตัวดำเนินการการรวมกันแบบ null โดยที่ค่าเริ่มต้นที่คุณต้องการใช้นั้นเป็นค่าเริ่มต้นสำหรับประเภท :
string s = myval ?? "";
สามารถเขียนใน Powershell เป็น:
([string]myval)
หรือ
int d = myval ?? 0;
แปลเป็น Powershell:
([int]myval)
ฉันพบว่าสิ่งแรกที่มีประโยชน์เหล่านี้เมื่อประมวลผลองค์ประกอบ xml ที่อาจไม่มีอยู่และหากมีอยู่อาจมีช่องว่างที่ไม่ต้องการล้อมรอบ:
$name = ([string]$row.td[0]).Trim()
Cast to string ป้องกันไม่ให้องค์ประกอบเป็นโมฆะและป้องกันความเสี่ยงที่จะTrim()
ล้มเหลว
([string]$null)
-> ""
ดูเหมือนเป็น "ผลข้างเคียงที่มีประโยชน์ แต่โชคร้าย" :(
$null, $null, 3 | Select -First 1
ผลตอบแทน
3
หากคุณติดตั้งโมดูลส่วนขยายชุมชน Powershellคุณสามารถใช้:
?? เป็นนามแฝงสำหรับ 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,"val1","val2",5) | select -First 1
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]
}
บ่อยครั้งที่ฉันพบว่าฉันต้องถือว่าสตริงว่างเป็นโมฆะเมื่อใช้การรวมกัน ฉันลงเอยด้วยการเขียนฟังก์ชันสำหรับสิ่งนี้ซึ่งใช้โซลูชันของZenexerสำหรับการรวมกันสำหรับการรวมกันเป็นโมฆะอย่างง่ายจากนั้นใช้Keith Hillสำหรับการตรวจสอบค่าว่างหรือค่าว่างและเพิ่มสิ่งนั้นเป็นค่าสถานะเพื่อให้ฟังก์ชันของฉันสามารถทำได้ทั้งสองอย่าง
ข้อดีอย่างหนึ่งของฟังก์ชันนี้คือมันยังจัดการกับองค์ประกอบทั้งหมดที่เป็นโมฆะ (หรือว่างเปล่า) โดยไม่มีข้อยกเว้น นอกจากนี้ยังสามารถใช้สำหรับตัวแปรอินพุตจำนวนมากโดยพลการด้วยวิธีที่ 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"
ฉันใช้ตัวดำเนินการการรวมกันเป็นโมฆะสำหรับข้างต้นดังนี้:
function NullCoalesc {
param (
[Parameter(ValueFromPipeline=$true)]$Value,
[Parameter(Position=0)]$Default
)
if ($Value) { $Value } else { $Default }
}
Set-Alias -Name "??" -Value NullCoalesc
ตัวดำเนินการที่มีเงื่อนไขสามารถนำไปใช้ในลักษณะที่คล้ายคลึงกัน
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"