You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET反射对象属性调用ToString格式化时抛出异常的问题求助

问题:通过反射格式化Int32属性值时抛出转换异常

我可以直接把Int32类型的变量I1格式化为货币格式,输出I1 = $31,742,但通过反射获取类的Int32属性信息、属性值和格式字符串后,无法完成格式化。在GetPropertyString方法中,调试显示Value的类型确实是Int32,但执行语句Dim Value2 As String = Value.ToString(HandlerFormatProvider)时抛出以下异常:

System.InvalidCastException
  HResult=0x80004002
  Message=Conversion from string "C0" to type 'Integer' is not valid.
  Source=Microsoft.VisualBasic
  StackTrace:
   at Microsoft.VisualBasic.CompilerServices.Conversions.ToInteger(String Value)
   at PropertyInfoType.Module1.GetPropertyString[T](T TObject) in C:\Data\VBS.NET\PropertyInfoType\PropertyInfoType\Module1.vb:line 36
   at PropertyInfoType.Module1.Main() in C:\Data\VBS.NET\PropertyInfoType\PropertyInfoType\Module1.vb:line 9

我搞不懂为什么这句代码会试图把"C0"转换成Int32?以下是复现问题的完整代码,请问如何通过反射获取的格式字符串来格式化属性值?我希望能在多个类上复用IPropertyHandler接口。

Module Module1

   Sub Main()
      Dim I1 As Int32 = 31742
      Dim P1 As String = "C0"
      Console.WriteLine("I1 = " & I1.ToString(P1) & ".")

      Dim F1 As Foo = New Foo(4217)
      Dim PropertyHandlerValue As String = GetPropertyString(Of Foo)(F1)
      Console.WriteLine("PropertyHandlerValue = " & PropertyHandlerValue.ToString & ".")

      Console.ReadLine()
   End Sub

   Public Function GetPropertyString(Of T)(ByVal TObject As T) As String
      GetPropertyString = Nothing
      If TypeOf TObject Is IPropertyHandler Then
         Dim SourceObject As IPropertyHandler = CType(TObject, IPropertyHandler)

         Dim HandlerPropertyName As String = SourceObject.PropertyHandlerName
         Dim HandlerFormatProvider As String = SourceObject.PropertyHandlerFormatProvider

         Dim SourcePropertyInfo As System.Reflection.PropertyInfo = GetType(T).GetProperty(HandlerPropertyName)

         If SourcePropertyInfo IsNot Nothing Then
            Dim SourcePropertyValue As Object = SourcePropertyInfo.GetValue(SourceObject)
            If String.IsNullOrEmpty(HandlerFormatProvider) Then
               GetPropertyString = SourcePropertyValue.ToString
            Else
               Dim Value As Object = System.Convert.ChangeType(SourcePropertyValue, SourcePropertyInfo.PropertyType)
               Dim Value2 As String = Value.ToString(HandlerFormatProvider)
               GetPropertyString = Value2
            End If
         End If
      Else
         Throw New System.NotImplementedException("The TObject passed in does not implement IPropertyHandler.")
      End If
   End Function

   Public Interface IPropertyHandler
      ReadOnly Property PropertyHandlerName As String
      ReadOnly Property PropertyHandlerFormatProvider As String
   End Interface

   Public Class Foo
      Implements IPropertyHandler
      Private m_SomeInt32 As Int32 = 0
      Private m_PropertyHandlerName As String = "SomeInt32"
      Private m_PropertyHandlerFormatProvider As String = "C0"
      'Private m_PropertyHandlerFormatProvider As String = ""
      Public Sub New(ByVal SomeInt32 As Int32)
         m_SomeInt32 = SomeInt32
      End Sub
      Public Property SomeInt32 As Int32
         Get
            Return m_SomeInt32
         End Get
         Set(value As Int32)
            m_SomeInt32 = value
         End Set
      End Property
      Public ReadOnly Property PropertyHandlerName As String Implements IPropertyHandler.PropertyHandlerName
         Get
            Return m_PropertyHandlerName
         End Get
      End Property

      Public ReadOnly Property PropertyHandlerFormatProvider As String Implements IPropertyHandler.PropertyHandlerFormatProvider
         Get
            Return m_PropertyHandlerFormatProvider
         End Get
      End Property
   End Class

End Module

问题原因

当Value是Object类型时,调用ToString(String)会触发Visual Basic的扩展方法解析优先级问题:VB会优先选择Microsoft.VisualBasic.Strings.ToString这个扩展方法,而不是Int32.ToString(String)实例方法。前者的参数要求是转换目标类型(比如"Integer"),而不是格式字符串,所以它会尝试把"C0"转换成Integer类型,导致异常。

解决方法

要确保调用的是值类型的实例ToString(String)方法,有两种可行方案:

方案1:使用String.Format替代直接调用ToString

这是通用性最强的方案,无需担心类型匹配问题,直接修改格式化逻辑:

GetPropertyString = String.Format("{0:" & HandlerFormatProvider & "}", SourcePropertyValue)

方案2:通过IConvertible接口明确调用实例方法

如果需要更精细的控制,可以利用数值类型实现的IConvertible接口,明确指定格式字符串和文化信息:

If TypeOf SourcePropertyValue Is IConvertible Then
    Dim convertibleValue = DirectCast(SourcePropertyValue, IConvertible)
    GetPropertyString = convertibleValue.ToString(HandlerFormatProvider, System.Globalization.CultureInfo.CurrentCulture)
Else
    GetPropertyString = SourcePropertyValue.ToString()
End If

优化后的GetPropertyString方法示例

Public Function GetPropertyString(Of T)(ByVal TObject As T) As String
    GetPropertyString = Nothing
    If TypeOf TObject Is IPropertyHandler Then
        Dim SourceObject As IPropertyHandler = CType(TObject, IPropertyHandler)

        Dim HandlerPropertyName As String = SourceObject.PropertyHandlerName
        Dim HandlerFormatProvider As String = SourceObject.PropertyHandlerFormatProvider

        Dim SourcePropertyInfo As System.Reflection.PropertyInfo = GetType(T).GetProperty(HandlerPropertyName)

        If SourcePropertyInfo IsNot Nothing Then
            Dim SourcePropertyValue As Object = SourcePropertyInfo.GetValue(SourceObject)
            If String.IsNullOrEmpty(HandlerFormatProvider) Then
                GetPropertyString = SourcePropertyValue.ToString
            Else
                ' 使用String.Format实现通用格式化
                GetPropertyString = String.Format("{0:" & HandlerFormatProvider & "}", SourcePropertyValue)
            End If
        End If
    Else
        Throw New System.NotImplementedException("传入的对象未实现IPropertyHandler接口。")
    End If
End Function

额外说明

String.Format方案无需额外修改即可支持DateTime、Decimal等其他可格式化类型,完全满足多类复用IPropertyHandler接口的需求。

内容的提问来源于stack exchange,提问作者BandannaMan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 23:54:51