7

我在 .NET 中看到了许多将 an 转换Object为 a的方法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)

是否有微软推荐的方法,或者这些方法都编译成相同的字节码?

编辑:

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

这些方法之间有什么区别?我看不到引擎盖下发生了什么,所以很高兴知道其中一个是否比其他的有任何性能优势。在某些情况下,这些调用可能会进行数千次(例如从大表中读取),并且减少几秒钟可能会对用户体验产生重大影响。

4

3 回答 3

12

Convert.ToString(x)即使 x 为空,也可以正常工作。 一般来说,在处理来自数据库的东西时,我认为 Convert 是最好的方法。另一个建议是,在使用浮点数/十进制数时,请留意 CultureInfo,即不要相信 . 作为十进制符号,如果你想假设使用CultureInfo.InvariantCulture.

于 2012-07-05T15:49:44.483 回答
1

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

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

我不是很肯定,但我怀疑当您进行连接时"" & x,它会转换x为 a String,在这种情况下,它是输入"" & CType(x, String)or的快捷方式"" & CStr(x)。每种类型都可以重载强制转换运算符,因此它假定类型(在这种情况下Int32)已经重载了运算符,因此可以强制转换为字符串。事实上,它已经并且可以。

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

至于首选方法x.ToString()是什么,我想说的是您一直最想使用的方法,除非您有其他问题(这完全取决于您对对象所做的事情)。

于 2012-07-05T16:00:28.147 回答
1

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

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

使用自定义对象的结果:不适用 没有自定义对象
结果:平均126.7 毫秒,中位数126 毫秒

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

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

因此,对于非常大的记录集来说,这似乎If(x, "").ToString()有点快,但这需要与Convert.ToString()'s 更强大的转换选项相平衡。感谢您的回答。

这是我用于测试的代码:

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
于 2012-07-05T17:23:05.103 回答