2012-07-05 3 views
6

Objectを.NETの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が推奨される方法がある、またはこれらはすべて同じバイトコードにダウンコンパイルするには?

EDIT:

私が含まれるように、質問を少し拡大してみましょう:

これらの方法の違いは何ですか?私はボンネットの下で何が起こっているのか見当がつかないので、他のものに比べてパフォーマンス上の利点があるかどうかを知ることは良いことです。場合によっては、これらの呼び出しが数千回(大きなテーブルからの読み込みなど)行われ、数秒のシェービングがUXの大きな影響を与えることがあります。

答えて

9

Convert.ToString(x)は、xがnullでも正常に機能します。 egeneralでは、データベースからのものを扱うときは、Convertが最良のアプローチだと思います。もう一つの提案は、浮動小数点/十進数で作業するとき、CultureInfoに目を留めてください。小数点記号として、CultureInfo.InvariantCultureを使用すると仮定する場合は、

+0

では、この問題をMicrosoftの推奨標準であれば、あなたは知っていますか?他の2つの方法と比べて、オーバーヘッドが導入されているかどうか、考えてください。私はCLRの忍者ではないので、実際にバイトコードレベルで比較することはできません。 – JDB

+0

パフォーマンスの面では、物事は賢く変わらないと思いますが、より安全である方が良いです。 –

+0

ありがとうございます - これは最も有益な答えでした。私はテスト結果に答えを加え、基本的にあなたの提案を確認しました。 – JDB

1

これは異なるものです。それらは異なるMSILコードにコンパイルされますが、ほとんどの場合、おそらく同じ結果が出ます。

ToStringは、すべてのオブジェクトに固有の基本タイプであるObjectによって定義されるメソッドです。デフォルトでは、オブジェクトの型名が返されますが、より意味のある文字列を返すように各型によってオーバーライドできます(しばしば)。たとえば、あなたの例では、xInt32オブジェクトであり、Int32ToStringをオーバーライドするので、デフォルトの "System.Int32"の代わりに"3"を返します。

私は肯定的ではないんだけど、私はあなたが連結"" & xを行うときに、それが"" & CType(x, String)または"" & CStr(x)を入力するためのショートカットである場合にはStringxを落としている疑いがあります。各型はキャスト演算子をオーバーロードする可能性があるため、型(この場合はInt32)が演算子をオーバーロードしているため、文字列にキャストできます。確かにそれはあります。

Convert.ToStringは、どの過負荷を呼び出すかによって異なることがあります。 Int32を渡すと、オブジェクトのToString()メソッドが呼び出されます。しかし、たとえばObjectを渡すと、オブジェクトがIConvertibleまたはIFormattableを実装しているかどうかが最初にチェックされます。存在する場合は、そのうちの1つを使用し、そうでない場合はToStringメソッドを使用します。そのため、送信するオブジェクトのタイプに応じて、そのタイプを文字列に変換する最も可能性の高い方法を判断するために試行します。

好きな方法は、私がx.ToString()と言っているのは、あなたがオブジェクトを使って何をしているのかに依存する他の懸念がない限り、ほとんどの時間を使いたいということです。

+0

私はCStr(DBNull.Value)がInvalidCastExceptionを引き起こしますが、DBNull.Valueは発生しないことを発見しました。だから私はそれがオブジェクトを文字列型にキャストしているとは思わない。しかし、 ""&何も動作しないので、必ずToString()を呼び出すとは思わない。 – JDB

+0

Convert.ToStringの強化された機能を指摘してくれてありがとうございました。追加されたリフレクションは、ToString()の呼び出しと比較して機能が少し遅くなりますが、違いは(以下の私の答えを参照してください)無視できます。 – JDB

1

私は、1,000,000個のオブジェクトのコレクションを使用して各メソッドのパフォーマンスをテストすることにしました。オブジェクトは、整数、クラス、NothingまたはDBNull.Valueのいずれかです。同じコレクションを各テストに使用し、各メソッドを50回テストしました。

"" & x
これは実際にはすべてのオブジェクトで機能しません。これはDBNull.ValueとNothingで機能しますが、このメソッドを単にオブジェクトで使用しようとするとInvalidCastExceptionが発生します。興味深いことに、CStr(DBNull.Value)はInvalidCastExceptionをスローします。その理由はわかりません。カスタムオブジェクトと

結果:N// OカスタムオブジェクトW
結果:140.46 MS平均:メジアン126.7 MS126のMSカスタムオブジェクトと

If(x, "").ToString()
結果の平均/ OカスタムオブジェクトW
、メジアン138ミリ
結果:69.32 MS平均、中央値69ミリ秒カスタムオブジェクトと

Convert.ToString()
結果:171.54 MS平均、メジアン171ミリ
/OカスタムオブジェクトWの結果:112.14 MS平均、メジアン112 MS

だから、If(x, "").ToString()は非常に大きなレコードセットでは少し速いと思われますが、それはConvert.ToString()のより多くのpoweとバランスを取る必要がありますrful変換オプション。答えをありがとう。

ここで私はテストのために使用するコードです:

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 
関連する問題