我已经看到了在.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产生巨大影响。
答案 0 :(得分:12)
即使x为null,Convert.ToString(x)
也能正常工作。一般来说,在处理来自数据库的东西时,我认为转换是最好的方法。另一个建议,当使用浮点数/十进制数时,请关注CultureInfo,即不要信任。作为十进制符号,如果您想假设使用CultureInfo.InvariantCulture
。
答案 1 :(得分:1)
他们做不同的事情。它们编译为不同的MSIL代码,但在大多数情况下,它们可能会有相同的结果。
ToString
是由Object
定义的方法,它是所有对象的固有基本类型。默认情况下,它返回对象的类型名称,但它可以(通常)被每种类型覆盖,以便返回更有意义的字符串。例如,在您的示例中,x
是Int32
对象,Int32
会覆盖ToString
,因此它返回"3"
而不是默认的“System.Int32”
我不是肯定的,但是我怀疑当你进行连接"" & x
时,它会将x
转换为String
,在这种情况下,它是键入{{"" & CType(x, String)
的快捷方式。 1}}或"" & CStr(x)
。每种类型都可以重载转换操作符,因此它假定类型(在这种情况下为Int32
)已经重载了操作符,因此可以强制转换为字符串。确实它已经并且可以。
Convert.ToString
会根据您调用的重载执行不同的操作。如果您传递Int32
,它只会调用对象的ToString()
方法。但是,例如,如果您传递Object
,它首先会检查对象是否实现IConvertible
或IFormattable
。如果是,则使用其中一个,否则使用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