2012-07-05 15 views
6

Ho visto un certo numero di modi per convertire uno Object in uno String in .NET, in genere per visualizzare il valore dell'oggetto per l'utente quando il tipo di oggetto non è noto.Procedura consigliata per convertire un oggetto in stringa

Questi includono:

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) 

Esiste un metodo che è raccomandato da Microsoft, o non tutti questi compilare verso il basso per lo stesso codice di byte?

EDIT:

Lasciate che vi spieghi la questione un po 'per includere:

Quali sono le differenze tra questi metodi? Non riesco a vedere cosa sta succedendo sotto il cofano, quindi sarebbe bello sapere se c'è un vantaggio sulle prestazioni di uno rispetto agli altri. In alcuni casi, queste chiamate possono essere fatte diverse migliaia di volte (come la lettura da un grande tavolo) e la rasatura di un paio di secondi può causare un grande impatto sulla UX.

risposta

9

Convert.ToString(x) funziona anche se x è nullo. In egneral, quando si tratta di cose provenienti dal database, penso che Convert sia l'approccio migliore. Un altro suggerimento, quando si lavora con numeri float/decimali, tenere d'occhio il CultureInfo, cioè non fidarsi del. come segno decimale, se si vuole assumere che usi CultureInfo.InvariantCulture.

+0

fai a sapere se si tratta di standard raccomandato di Microsoft? Qualche idea su quale sia l'eventuale overhead introdotto rispetto agli altri due metodi? Non sono molto un ninja CLR, quindi non posso davvero confrontarli a livello di codice byte. – JDB

+0

Penso che in termini di prestazioni le cose non cambino sensibilmente, è meglio essere più sicuri. –

+0

Grazie - questa è stata la risposta più utile. Ho aggiunto una risposta con i risultati del test e sostanzialmente ha confermato il tuo suggerimento. – JDB

1

Fanno cose diverse. Si compilano con codici MSIL diversi, ma nella maggior parte dei casi avranno probabilmente lo stesso risultato.

ToString è un metodo definito da Object, che è il tipo di base inerente per tutti gli oggetti. Di default restituisce il nome del tipo dell'oggetto, ma può (e spesso è) sovrascritto da ciascun tipo in modo che restituisca una stringa più significativa. Ad esempio, nel tuo esempio, x è un oggetto Int32 e Int32 esegue l'override ToString in modo che restituisca "3" anziché il "System.Int32" predefinito.

io non sono positivi, ma ho il sospetto quando si esegue la concatenazione "" & x, si è colata x ad un String, nel qual caso si tratta di una scorciatoia per la digitazione "" & CType(x, String) o "" & CStr(x). Ogni tipo può sovraccaricare l'operatore di casting, quindi presuppone che il tipo (in questo caso Int32) abbia sovraccaricato l'operatore e possa quindi essere trasmesso su una stringa. In effetti ha e può.

Convert.ToString fa cose diverse a seconda di quale sovraccarico si chiama. Se lo passi un Int32, chiama solo il metodo ToString() dell'oggetto. Tuttavia, se lo si passa a Object, ad esempio, prima controlla se l'oggetto implementa IConvertible o IFormattable. Se lo fa, ne usa uno, altrimenti usa il metodo ToString. Quindi, in base al tipo di oggetto che si invia, prova a determinare quale sia il modo migliore per ottenere quel tipo su una stringa.

Per quanto riguarda il metodo preferito, direi che x.ToString() è ciò che si desidera utilizzare la maggior parte del tempo, a meno che non si abbia qualche altra preoccupazione (che dipende tutto da cosa si sta facendo con l'oggetto).

+0

Ho scoperto che CStr (DBNull.Value) causerà InvalidCastException, ma "" e DBNull.Value no. Quindi non penso che stia lanciando l'oggetto per scrivere una stringa. Ma, "" & Niente funziona anche, quindi non penso che debba necessariamente chiamare ToString(). – JDB

+0

Grazie per aver sottolineato le funzionalità avanzate di Convert.ToString - non si è reso conto che ha fatto tutto questo. La riflessione aggiunta rallenta leggermente la funzione rispetto alla chiamata a ToString(), ma la differenza (vedi la mia risposta sotto) è trascurabile. – JDB

1

Ho deciso di testare le prestazioni di ciascun metodo utilizzando una raccolta di 1.000.000 di oggetti. Gli oggetti erano uno: un numero intero, una classe, Nothing o DBNull.Value. La stessa collezione è stata utilizzata per ciascun test e ho testato ogni metodo 50 volte.

"" & x
Questo in realtà non funziona per tutti gli oggetti. Funziona per DBNull.Value e Nothing, ma provare a utilizzare questo metodo con un qualsiasi oggetto qualsiasi causerà InvalidCastException. È interessante notare che CStr (DBNull.Value) genera una InvalidCastException, quindi non sono sicuro del motivo per cui funziona.

Risultati con oggetto personalizzato: N/A
Risultati w/o oggetto personalizzato: avg 126,7 ms, mediana 126 ms

If(x, "").ToString()
risultati con oggetto personalizzato: avg 140.46 ms, mediano 138 ms
Risultati senza oggetto personalizzato: avg 69,32 ms, mediana 69 ms

Convert.ToString()
Risultati con oggetto personalizzato: Media 171.54 ms, mediana 171 ms
Risultati w/o oggetto personalizzato: avg 112.14 ms, mediana 112 ms

Quindi sembrerebbe che If(x, "").ToString() sia un po 'più veloce per un set di record molto grande, ma che dovrebbe essere bilanciato con il Convert.ToString() opzioni di conversione rful. Grazie per le risposte.

Ecco il codice che ho usato per il test:

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 
Problemi correlati