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
你显然有
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"))