将对象转换为字符串的最佳实践

时间:2012-07-05 15:46:16

标签: .net vb.net

我已经看到了在.NET中将Object转换为String的多种方法,通常用于在对象类型未知时向用户显示对象的值。

这些包括:

Dim x as Object = 3
Dim y as Object = Nothing
Dim z as Object = DBNull.Value
Dim l_displayString As String

l_displayString = "" & x & "" & y & "" & z
l_displayString = If(x, "").ToString() & If(y, "").ToString() & If(z, "").ToString()
l_displayString = Convert.ToString(x) & Convert.ToString(y) & Convert.ToString(z)

是否有Microsoft推荐的方法,或者这些方法是否都编译为相同的字节代码?

编辑:

让我稍微扩展一下这个问题:

这些方法有什么区别?我看不清底下发生了什么,所以很高兴知道一个人是否有任何性能优势。在某些情况下,这些调用可能会进行数千次(例如从大型表中读取),并且在几秒钟内完成调整可能会对UX产生巨大影响。

3 个答案:

答案 0 :(得分:12)

即使x为null,Convert.ToString(x)也能正常工作。一般来说,在处理来自数据库的东西时,我认为转换是最好的方法。另一个建议,当使用浮点数/十进制数时,请关注CultureInfo,即不要信任。作为十进制符号,如果您想假设使用CultureInfo.InvariantCulture

答案 1 :(得分:1)

他们做不同的事情。它们编译为不同的MSIL代码,但在大多数情况下,它们可能会有相同的结果。

ToString是由Object定义的方法,它是所有对象的固有基本类型。默认情况下,它返回对象的类型名称,但它可以(通常)被每种类型覆盖,以便返回更有意义的字符串。例如,在您的示例中,xInt32对象,Int32会覆盖ToString,因此它返回"3"而不是默认的“System.Int32”

我不是肯定的,但是我怀疑当你进行连接"" & x时,它会将x转换为String,在这种情况下,它是键入{{"" & CType(x, String)的快捷方式。 1}}或"" & CStr(x)。每种类型都可以重载转换操作符,因此它假定类型(在这种情况下为Int32)已经重载了操作符,因此可以强制转换为字符串。确实它已经并且可以。

Convert.ToString会根据您调用的重载执行不同的操作。如果您传递Int32,它只会调用对象的ToString()方法。但是,例如,如果您传递Object,它首先会检查对象是否实现IConvertibleIFormattable。如果是,则使用其中一个,否则使用ToString方法。因此,它根据您发送它的对象类型尝试确定它认为最有可能将该类型转换为字符串的最佳方式。

至于什么是首选方法,我会说x.ToString()是你想要一直使用的最多的东西,除非你有其他一些问题(这完全取决于你对对象做了什么) )。

答案 2 :(得分:1)

我决定使用1,000,000个对象的集合来测试每个方法的性能。对象是以下之一:整数,类,Nothing或DBNull.Value。每次测试都使用相同的集合,我测试了每种方法50次。

"" & x
这实际上并不适用于所有对象。它适用于DBNull.Value和Nothing,但尝试将此方法与任何ol'对象一起使用将导致InvalidCastException。有趣的是,CStr(DBNull.Value)抛出一个InvalidCastException,所以我不确定它为什么会起作用。

自定义对象的结果: N / A
没有自定义对象的结果:平均 126.7毫秒,中位数 126毫秒

If(x, "").ToString()
自定义对象的结果:平均值 140.46毫秒,中位数 138毫秒
结果没有自定义对象:平均 69.32毫秒,中位数 69毫秒

Convert.ToString()
自定义对象的结果:平均值 171.54毫秒,中位数 171毫秒
没有自定义对象的结果:平均 112.14 ms ,中位数 112 ms

因此,If(x, "").ToString()对于大量记录来说似乎更快一些,但这需要与Convert.ToString()更强大的转换选项进行平衡。谢谢你的回答。

这是我用于测试的代码:

Option Strict Off

Module Module1

    Sub Main()
        Dim l_objectArray = Enumerable.Range(0, 1000000).Select(Function(x) GetObject(x)).ToArray()

        Dim l_stopWatch As New Stopwatch()
        Dim l_testResults As New List(Of Long)
        Dim l_testIterations As Integer = 50
        Dim l_displayValue As String

        Do

            ' --------------------

            'Console.WriteLine()
            'Console.WriteLine("Conversion using string concatenation")
            'l_testResults.Clear()

            'For iteration = 0 To l_testIterations - 1
            '    l_stopWatch.Start()
            '    For Each o In l_objectArray
            '        l_displayValue = "" & o
            '    Next
            '    l_stopWatch.Stop()
            '    l_testResults.Add(l_stopWatch.ElapsedMilliseconds)
            '    l_stopWatch.Reset()
            'Next

            'Console.WriteLine()
            'Console.WriteLine("Average: " & l_testResults.Average())
            'Console.WriteLine("Median: " & GetMedian(l_testResults.ToArray()))

            ' --------------------

            Console.WriteLine()
            Console.WriteLine("Conversion using Object.ToString()")
            l_testResults.Clear()

            For iteration = 0 To l_testIterations - 1
                l_stopWatch.Start()
                For Each o In l_objectArray
                    l_displayValue = If(o, "").ToString()
                Next
                l_stopWatch.Stop()
                l_testResults.Add(l_stopWatch.ElapsedMilliseconds)
                l_stopWatch.Reset()
            Next

            Console.WriteLine()
            Console.WriteLine("Average: " & l_testResults.Average())
            Console.WriteLine("Median: " & GetMedian(l_testResults.ToArray()))

            ' --------------------

            Console.WriteLine()
            Console.WriteLine("Conversion using Convert.ToString(x)")
            l_testResults.Clear()

            For iteration = 0 To l_testIterations - 1
                l_stopWatch.Start()
                For Each o In l_objectArray
                    l_displayValue = Convert.ToString(o)
                Next
                l_stopWatch.Stop()
                l_testResults.Add(l_stopWatch.ElapsedMilliseconds)
                l_stopWatch.Reset()
            Next

            Console.WriteLine()
            Console.WriteLine("Average: " & l_testResults.Average())
            Console.WriteLine("Median: " & GetMedian(l_testResults.ToArray()))

            ' --------------------

            Console.WriteLine()
            Console.Write("Exit? (y/n): ")
            Dim l_key = Console.ReadKey(False)
            If l_key.Key = ConsoleKey.Y Then
                Exit Sub
            End If

        Loop

    End Sub

    Private Function GetMedian(ByVal values As Long()) As Long
        Array.Sort(values)
        If values.Length Mod 2 = 0 Then
            Return (values(values.Length / 2) + values(values.Length / 2 - 1)) / 2
        Else
            Return values(CInt(Math.Floor(values.Length / 2)))
        End If
    End Function

    Private Function GetObject(ByVal someNumber As Integer) As Object
        Select Case someNumber Mod 4
            Case 0
                Return someNumber
            Case 1
                Return New SomeClass(someNumber)
                'Return Nothing
            Case 2
                Return DBNull.Value
            Case Else
                Return Nothing
        End Select
    End Function

    Private Class SomeClass

        Private _seed As Integer

        Public Sub New(ByVal seed As Integer)
            _seed = seed
        End Sub

        Public Overrides Function ToString() As String
            Return _seed.ToString()
        End Function

    End Class

End Module