格式化 DataRow.Item 抛出 System.InvalidCastException - 为什么?

问题描述 投票:0回答:1

VS 2022 社区 17.5.3,控制台应用程序。 下面最后一个 Console.WriteLine 抛出 InvalidCastException。

Module Module1
   Dim DT1 As DataTable = New DataTable("DT1")

   ' Add a column to the DataTable
   Dim FieldType As Type = GetType(System.Int64)
   Dim MyColumn As DataColumn = New DataColumn("Col1", FieldType)
   DT1.Columns.Add(MyColumn)

   ' Add a Row to the DataTable and populate it
   Dim NewRow As DataRow = DT1.NewRow
   Dim RowArray() As Object = New Object() {1234}
   NewRow.ItemArray = RowArray
   DT1.Rows.Add(NewRow)

   ' Display formatted value from Row, Col1
   Console.WriteLine("Col1 Value = " & NewRow.Item("Col1"))
   Console.WriteLine("Col1 Type = " & NewRow.Item("Col1").GetType.ToString)
   Console.WriteLine("Col1 Formatted Value = " & NewRow.Item("Col1").ToString("N0"))

End Sub

输出是: Col1 值 = 1234 Col1 类型 = System.Int64

然后,调试器启动:

System.InvalidCastException
  HResult=0x80004002
  Message=Conversion from string "N0" to type 'Integer' is not valid.
  Source=Microsoft.VisualBasic
  StackTrace:
   at Microsoft.VisualBasic.CompilerServices.Conversions.ToInteger(String Value) in f:\dd\vb\runtime\msvbalib\Helpers\Conversions.vb:line 788
   at ConsoleTest.Module1.Main() in C:\Data\VB.NET\ConsoleTest\ConsoleTest\Module1.vb:line 1434

  This exception was originally thrown at this call stack:
    Microsoft.VisualBasic.CompilerServices.Conversions.ParseDouble(String, System.Globalization.NumberFormatInfo) in Conversions.vb
    Microsoft.VisualBasic.CompilerServices.Conversions.ParseDouble(String) in Conversions.vb
    Microsoft.VisualBasic.CompilerServices.Conversions.ToInteger(String) in Conversions.vb

Inner Exception 1:
FormatException: Input string was not in a correct format.

为什么我不能使用 ("N0") 作为 ToString 格式选项?该列的数据类型为 Int64 但将其转换为字符串 (ToString) 似乎将格式文本 ("N0") 视为数组的索引而不是格式代码。

如果不是行:

    Console.WriteLine("Col1 Formatted Value = " & NewRow.Item("Col1").ToString("N0"))

我用:

    Dim MyInt64 As Int64 = NewRow.Item("Col1")
    Console.WriteLine("Col1 Value Formatted = " & MyInt64.ToString("N0"))

我得到了想要的和预期的结果: Col1 格式化值 = 1,234

vb.net datatable formatting
1个回答
1
投票

你显然有

Option Strict Off
如果这有效:

Dim MyInt64 As Int64 = NewRow.Item("Col1")

DataRow.Item
属性是
Object
类型,因此代码依赖于从
Object
Long
的隐式缩小转换,这对于
Option Strict On
是不允许的。这是为什么你应该总是有
Option Strict On
的例子。它迫使您明确输入内容,以免造成混淆。事实上,您依靠系统来猜测您的意思,虽然它在大多数时候都会正确,但有时它会出错。这是那些时代之一。这里:

Dim MyInt64 As Int64 = NewRow.Item("Col1")
Console.WriteLine("Col1 Value Formatted = " & MyInt64.ToString("N0"))

你在一个

ToString
值上调用
Long
这样系统就知道你想要调用什么重载。这里:

Console.WriteLine("Col1 Formatted Value = " & NewRow.Item("Col1").ToString("N0"))

系统实际上认为您正在调用不带参数的

Object.ToString
方法,然后索引生成的
String
以在该索引处获得
Char
。因为 VB 允许您在调用不带参数的方法时省略空的括号,所以它将代码解释为:

Console.WriteLine("Col1 Formatted Value = " & NewRow.Item("Col1").ToString()("N0"))

与此相同:

Console.WriteLine("Col1 Formatted Value = " & NewRow.Item("Col1").ToString().Chars("N0"))

Chars
属性需要一个
Integer
索引,但是
String
“N0” 不能转换为
Integer
,所以这就是错误消息告诉你的内容。因为你有
Option Strict Off
,所以这些检查都不会在运行时发生,而不是在编译时被捕获。

解决方案是始终拥有

Option Strict On
并明确输入。您可以在项目属性中将其设置为
On
,您还应该在VS选项中将其设置为
On
,以便所有未来项目默认为
On
。一旦它是
On
,您可能会在代码依赖于隐式转换和后期绑定的地方遇到很多错误,因此您必须通过适当的强制转换或转换来修复每个错误。

这里的具体解决方案是从

Long
中实际得到一个
DataRow
值然后你可以调用
ToString
的重载。有多种方法可以做到这一点,但我会这样做:

Console.WriteLine($"Col1 Formatted Value = {NewRow.Field(Of Long)("Col1"):N0}")

使用字符串插值来清理一些东西,这意味着无论如何都不需要直接调用

ToString
Field
方法是 LINQ to DataSet 的一部分,允许您获取特定类型的字段值。请注意,您还可以使用
Console.WriteLine
:

中内置的复合格式
Console.WriteLine("Col1 Formatted Value = {0:N0}", NewRow.Field(Of Long)("Col1"))
© www.soinside.com 2019 - 2024. All rights reserved.