2012-07-05 11 views
6

Ich habe eine Reihe von Möglichkeiten zum Umwandeln einer Object in eine String in. NET, in der Regel zum Anzeigen des Objekts Wert für den Benutzer, wenn der Objekttyp nicht bekannt ist.Best Practice zum Konvertieren eines Objekts in Zeichenfolge

Dazu gehören:

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) 

Gibt es eine Methode, die von Microsoft empfohlen wird, oder haben diese alle auf den gleichen Bytecode kompiliert down?

EDIT:

Lassen Sie mich die Frage erweitern ein wenig umfassen:

Was sind die Unterschiede zwischen diesen Methoden sind? Ich kann nicht sehen, was unter der Motorhaube vor sich geht, also wäre es schön zu wissen, ob es irgendeinen Leistungsvorteil gegenüber den anderen gibt. In einigen Fällen können diese Anrufe mehrere tausend Mal ausgeführt werden (z. B. beim Lesen von einer großen Tabelle), und ein paar Sekunden langes Rasieren kann eine große UX-Auswirkung haben.

Antwort

9

Die Convert.ToString(x) funktioniert anmutig, auch wenn x null ist. Im Allgemeinen, wenn es um Daten aus der Datenbank geht, denke ich, dass Convert der beste Ansatz ist. Ein anderer Vorschlag, wenn man mit Float/Dezimalzahlen arbeitet, sollte CultureInfo im Auge behalten, dh man darf dem nicht vertrauen. als Dezimalzeichen, wenn Sie davon ausgehen wollen, dass CultureInfo.InvariantCulture verwendet wird.

+0

Wissen Sie, ob dies empfohlenen Standard von Microsoft? Gibt es irgendeine Idee, was, wenn überhaupt, Overhead gegenüber den anderen beiden Methoden eingeführt wird? Ich bin nicht viel von einem CLR-Ninja, also kann ich sie nicht wirklich auf Byte-Code-Ebene vergleichen. – JDB

+0

Ich denke, dass im Hinblick auf die Leistung Dinge nicht sinnvoll ändern, ist es besser, sicherer zu sein. –

+0

Danke - das war die hilfreichste Antwort. Ich fügte eine Antwort mit meinen Testergebnissen hinzu und bestätigte im Grunde Ihren Vorschlag. – JDB

1

Sie machen verschiedene Dinge. Sie kompilieren zu verschiedenen MSIL-Code, aber in den meisten Fällen werden sie wahrscheinlich das gleiche Ergebnis haben.

ToString ist eine Methode, die durch Object definiert wird. Dies ist der inhärente Basistyp für alle Objekte. Standardmäßig gibt sie den Typnamen des Objekts zurück, kann aber (und wird oft) von jedem Typ überschrieben werden, sodass er eine aussagekräftigere Zeichenfolge zurückgibt. In Ihrem Beispiel ist x ein Int32 Objekt und Int32 überschreibt ToString, so dass es "3" statt der Standard "System.Int32" zurückgibt.

Ich bin nicht positiv, aber ich vermute, wenn Sie die Verkettung tun "" & x, es x zu einem String wirft, in diesem Fall ist es eine Abkürzung "" & CType(x, String) oder "" & CStr(x) zu tippen. Jeder Typ kann den Casting-Operator überlasten, so dass angenommen wird, dass der Typ (in diesem Fall Int32) den Operator überlastet hat und daher in einen String umgewandelt werden kann. Tatsächlich hat und kann es.

Convert.ToString macht verschiedene Dinge abhängig davon, welche Überlast Sie anrufen. Wenn Sie eine Int32 übergeben, ruft es nur die Methode ToString() des Objekts auf. Wenn Sie jedoch eine Object übergeben, überprüft es zuerst, ob das Objekt IConvertible oder IFormattable implementiert. Wenn dies der Fall ist, wird eine davon verwendet, andernfalls wird die Methode ToString verwendet. Daher versucht es, abhängig von der Art des Objekts, das Sie senden, zu bestimmen, was es für die wahrscheinlich beste Methode hält, um diesen Typ in eine Zeichenfolge umzuwandeln.

Was ist die bevorzugte Methode, würde ich sagen, x.ToString() ist, was Sie die meiste Zeit verwenden möchten, es sei denn, Sie haben andere Bedenken (was alles davon abhängt, was Sie mit dem Objekt tun).

+0

Ich habe entdeckt, dass CStr (DBNull.Value) eine InvalidCastException verursacht, aber "" & DBNull.Value nicht. Ich denke also nicht, dass es das Objekt zum Eingeben von String ausgibt. Aber "" & Nichts funktioniert auch, also denke ich nicht, dass es unbedingt ToString() aufruft. – JDB

+0

Vielen Dank, dass Sie auf die erweiterten Funktionen von Convert.ToString hingewiesen haben. Die zusätzliche Reflektion verlangsamt die Funktion ein wenig im Vergleich zum Aufruf von ToString(), aber der Unterschied (siehe meine Antwort unten) ist vernachlässigbar. – JDB

1

Ich beschloss, die Leistung jeder Methode mit einer Sammlung von 1.000.000 Objekten zu testen. Die Objekte waren: eine Ganzzahl, eine Klasse, Nothing oder DBNull.Value. Die gleiche Sammlung wurde für jeden Test verwendet, und ich testete jede Methode 50 Mal.

"" & x
Dies funktioniert nicht für alle Objekte. Es funktioniert für DBNull.Value und Nothing, aber wenn Sie versuchen, diese Methode nur mit einem beliebigen Objekt zu verwenden, wird eine InvalidCastException ausgelöst. Interessanterweise löst CStr (DBNull.Value) eine InvalidCastException aus, weshalb ich mir nicht sicher bin, warum das funktioniert.

Ergebnisse mit benutzerdefinierten Objekt: N/A
Ergebnisse w/o benutzerdefiniertes Objekt: avg 126,7 ms, Median 126 ms

If(x, "").ToString()
Ergebnisse mit benutzerdefinierten Objekt: avg 140,46 ms, Median 138 ms
Ergebnisse ohne benutzerdefiniertes Objekt: Durchschnitt 69,32 ms, Median 69 ms

Convert.ToString()
Ergebnisse mit benutzerdefinierten Objekt: avg 171,54 ms, Median 171 ms
Ergebnisse w/o individuelle Objekt: avg 112,14 ms, Median 112 ms

So scheint es, dass If(x, "").ToString() ist ein bisschen schneller für eine sehr große Reihe von Datensätzen, aber das müsste mit Convert.ToString() mehr Leistung ausgeglichen werden rful Umrechnungsoptionen. Danke für die Antworten.

Hier ist der Code, den ich für den Test verwendet:

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