'float variable that should be empty or null is being set to 0
I'm working on a function that accepts [Single]$DurationMS as an optional parameter. This is supposed to be float value. So in my function I have the following code to check if its been provided to the function. if it is provided I want to add the value to an object nested in another object.
if ($DurationMS -ne $null) {
$MyObject.attributes | Add-Member -MemberType NoteProperty -Name 'duration.ms' -Value $DurationMS
}
All looks fine except when I test it I get 0 in the duration and I can't figure out why.
duration.ms
-----------
0
so my condition is evaluating to true but I don't understand why.
Solution 1:[1]
[single]is a .NET value type, and instances of such types can never be$null.[single].IsValueTypereturning$truetells you that it is a value type.$nullonly applies to .NET reference types and tells you that is a reference to no object.
It is therefore pointless to test your
[single]-typed$DurationMSparameter variable for being$null:- A
[single]instance's default value is0, so that your$DurationMS -ne $nullconditional is effectively0 -ne $nullby default, which is$true.
- A
The robust way to check if an argument was passed to a given (non-mandatory) parameter in a given invocation is to consult the automatic
$PSBoundParametersvariable, as Santiago Squarzon suggests.- This variable contains a dictionary that has entries for all explicitly passed arguments, keyed by their parameter names (sans prefix
-); e.g., if your function is invoked with-DurationMS 1.2,$PSBoundParameters['DurationMS']returns1.2, and$PSBoundParameters.ContainsKey('DurationMS')indicates$true
- This variable contains a dictionary that has entries for all explicitly passed arguments, keyed by their parameter names (sans prefix
Therefore:
# Was an argument passed to -DurationMS?
if ($PSBoundParameters.ContainsKey('DurationMS')) {
$MyObject.attributes |
Add-Member -MemberType NoteProperty -Name 'duration.ms' -Value $DurationMS
}
The following aspects are incidental:
if ($DurationMs)would only work if you also wanted to consider an explicit argument of0to signal "no value was provided", because with a[single]-typed$DurationMs,if ($DurationMs)is the same asif ($DurationMs -ne 0)- PowerShell allows you to use an expression of any type in a Boolean context; with numeric types,
0maps to$false, and any nonzero value to$true. - While this implicit to-Boolean conversion behavior is generally convenient, it has its pitfalls - see the bottom section of this answer for a summary of the rules.
- PowerShell allows you to use an expression of any type in a Boolean context; with numeric types,
Given that many PowerShell operators can implicitly operate on arrays (collections) as the LHS - in which case they act as filters, returning the subarray of matching items - it is generally better to place a scalar comparison operand on the LHS (in the case at we know that the non-literal operand is by definition also a scalar - a
[single]instance - so that doesn't matter).Placing the scalar on the LHS avoids false positives / negatives, such as in the following example:
$arr = 0, $null # !! -> 'null', because (0, $null) -ne $null filters the # !! array to @(0), and [bool] @() - perhaps surprisingly - is $false if ($arr -ne $null) { 'not null' } else { 'null' } # OK, with $null on the LHS # -> 'not null' if ($null -ne $arr) { 'not null' } else { 'null' }However, even on the LHS
$nullcan exhibit unexpected behavior, namely with the-lt,-le,-gt, and-geoperators, as discussed in this answer; e.g.:$null -lt 0 # !! -> $true - even though [int] $null yields 0If PowerShell offered a dedicated test for
$null, these pitfalls could be avoided; implementing such a test - in the form$var -is $nullor$var -isnull- was the subject of GitHub PR #10704; unfortunately, that PR was abandoned by its creator, and no one has picked up the work since, which is why no such test exists as of PowerShell 7.2.2.
As Lee Dailey points out, a property name such as
duration.mscan be problematic, given that it contains., which normally suggests a nested property access, given that an (unquoted).serves as the member-access operator.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
