使用 CType Int32?到 Int64? - System.InvalidCastException: 指定的转换无效

With CType Int32? to Int64? - System.InvalidCastException: Specified cast is not valid

为什么 CType 抱怨 (InvalidCastException) 获取对象(实际上是 Int32?)并将其转换为 Int64?

我发现 CTypeDynamic 没有问题(尽管是切线的,因为我专注于 Ctype)。

这是重现该场景的代码示例。

Module Module1

  Sub Main()

    Dim i As Int32? = 1234567891

    'manual nullable -> non nullable -> non nullable -> nullable
    'per 
    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

您有两个问题,都与编译时可用的类型信息不足有关。

  1. .NET 不专门化泛型方法。基于约束的一种编译必须对通用参数的每个 运行 时间值起作用。

    在编译器看到 xCType 时,它不知道 T 是可空类型,因此它无法选择可空转换规则(S?STT?),即使你限制为通用可为 null 的中间转换(ST)仍然会失败,因为那是类型-具体而非通用。

  2. obj 具有静态类型 Object,因此编译器再次不知道传入的实际值可以为 null,并且不能 select可为空的转换序列。当编译时类型信息丢失时,再次找不到序列中的中间转换(ST)。

CTypeDynamic 通过查看 运行time 类型而不是编译时类型来克服这两个问题。