Why is CType complaining (InvalidCastException
) about taking an object (that is really an Int32?
) and converting it to an Int64?
?
I've found that CTypeDynamic isn't having an issue (tangential though, as I'm focused on Ctype
).
Here is a code sample to reproduce the scenario.
Module Module1
Sub Main()
Dim i As Int32? = 1234567891
'manual nullable -> non nullable -> non nullable -> nullable
'per https://stackoverflow.com/a/10065482/392175
Dim iNotNullable As Int32 = i.Value
Dim biNotNullable As Int64 = iNotNullable
Dim bi As Int64? = biNotNullable
Console.WriteLine($"---Manual results---")
Console.WriteLine($"i={i}")
Console.WriteLine($"bi={bi}")
'CType investigation
bi = Module1.xCType(Of Int64?)(i)
Console.WriteLine($"---CType results---")
Console.WriteLine($"i={i}")
Console.WriteLine($"bi={bi}")
Console.ReadLine()
End Sub
Public Function [xCType](Of T)(ByVal obj As Object) As T
If obj Is Nothing Then Return Nothing
If IsDBNull(obj) Then Return Nothing
Return obj 'fails
Return CType(obj, T) 'fails
Return CTypeDynamic(Of T)(obj) 'succeeds
End Function
End Module
You have two problems, both related to insufficient type information available at compile time.
.NET doesn't specialize generic methods. One compilation, based on the constraints, has to work for every run-time value of the generic parameter.
At the time the compiler sees xCType
it doesn't know that T
is a nullable type, so it can't choose the rule for nullable cast (S?
to S
to T
to T?
) and even if you constrain to a generic nullable the middle conversion (S
to T
) will still fail because that's type-specific not generic.
obj
has static type Object
, so again the compiler doesn't know that the actual value passed in will be a nullable and cannot select the nullable conversion sequence. And again the middle conversion in the sequence (S
to T
) cannot be found when the compile-time type information is missing.
CTypeDynamic
overcomes both these problems, by looking at the runtime type instead of the compile-time type.