Reputation: 924
I have the following code that I don't believe is functioning properly and I cannot figure out why.
dim total as decimal? = If(first Is Nothing OrElse second Is Nothing, _
Nothing, _
Math.Abs(If(first, 0D)) - Math.Abs(If(second, 0D)))
If either first or second are nothing, then nothing needs to be placed in the total
. However, if they both have values, they both need to be changed to positive values and first - second
needs to be calculated. First and second are both nullable decimals (decimal?).
Expected results:
first = nothing
second = nothing
total = nothing
Actual results:
first = nothing
second = nothing
total = 0D
I cannot understand why the if statement is not jumping to the true segment and putting Nothing into the variable total
Upvotes: 0
Views: 215
Reputation: 924
I have reverted to make a compiler extension that allows the absolute value function to be performed on a nullable decimal, returning the value if it is Nothing or non-negative, otherwise multiply by -1 and return. That way if it returns nothing the computation result is as expected.
dim total as decimal? = first.ToAbsoluteValue() - second.ToAbsoluteValue()
<System.Runtime.CompilerServices.Extension()>
Friend Function ToAbsoluteValue(value As Decimal?) As Decimal?
If value Is Nothing OrElse value >= 0 Then Return value
Return Math.Abs(If(value, 0D))
End Function
If anyone knows how to add this to the Math.Abs() overloads that would be a much cleaner option.
Upvotes: 0
Reputation: 415705
The If()
operator is strongly-typed, but the compiler has to infer the type of the result based on the inputs.
In this case, it can't infer the type from the first option (Nothing
), because Nothing by itself has no type, and unlike C#'s null
, Nothing can reduce to a value type (this will be important in a moment). Therefore the compiler has to look at the second option: Math.Abs(If(first, 0D)) - Math.Abs(If(second, 0D))
. The type of this expression evaluates out to a Decimal
... not a Decimal?
. Therefore, the resulting type of your entire If()
expression is a Decimal
, and not a Decimal?
. That you assign the result to a Decimal?
doesn't matter.
I cannot understand why the if statement is not jumping to the true segment and putting Nothing into the variable total
That is exactly what it's doing. However, as mentioned earlier, Nothing
in VB.Net can be assigned to value types. Before the assignment can occur, Nothing is converted to a Decimal, because this is the result type of that If()
expression. In case of a Decimal, assigning the value of Nothing results in the default Decimal value of 0D
... hence your results.
I haven't tested this, but I think you could fix this to get your desired results by explicitly casting the False expression in your If()
operator as a Decimal?
/Nullable(Of Decimal)
. This will tell the compiler to infer Decimal?
instead of Decimal
for the type of the If()
expression, and therefore returning Nothing
from that expression will have desired output.
Upvotes: 2