2012-07-05 25 views
6

Tôi đã thấy một số cách để chuyển đổi Object thành một String trong .NET, thường để hiển thị giá trị của đối tượng cho người dùng khi loại đối tượng không được biết.Thực hành tốt nhất để chuyển đổi một đối tượng thành chuỗi

Chúng bao gồm:

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) 

Có một phương pháp được khuyến cáo của Microsoft, hay những bài biên dịch xuống để cùng mã byte?

EDIT:

Hãy để tôi mở rộng câu hỏi một chút để bao gồm:

sự khác biệt giữa các phương pháp này là gì? Tôi không thể nhìn thấy những gì đang xảy ra dưới mui xe, vì vậy nó sẽ được tốt đẹp để biết nếu có bất kỳ lợi ích hiệu suất của một trong những người khác. Trong một số trường hợp, các cuộc gọi này có thể được thực hiện vài nghìn lần (chẳng hạn như đọc từ một chiếc bàn lớn) và cạo một vài giây có thể tạo ra tác động lớn đến UX.

Trả lời

9

Convert.ToString(x) hoạt động hiệu quả ngay cả khi x là rỗng. Trong egneral, khi giao dịch với các công cụ đến từ cơ sở dữ liệu, tôi nghĩ rằng Chuyển đổi là cách tiếp cận tốt nhất. Một gợi ý khác, khi làm việc với các số float/decimal, hãy để mắt đến CultureInfo, tức là không tin tưởng. dưới dạng dấu thập phân, nếu bạn muốn giả sử sử dụng CultureInfo.InvariantCulture.

+0

Bạn có biết nếu điều này là tiêu chuẩn khuyến cáo của Microsoft? Bất kỳ ý tưởng gì, nếu có, chi phí được giới thiệu so với hai phương pháp khác? Tôi không phải là một ninja CLR, vì vậy tôi không thể so sánh chúng ở cấp mã byte. – JDB

+0

Tôi nghĩ rằng trong điều khoản của những điều hiệu suất không thay đổi một cách hợp lý, tốt hơn là an toàn hơn. –

+0

Cảm ơn - đây là câu trả lời hữu ích nhất. Tôi đã thêm một câu trả lời với kết quả kiểm tra của tôi và về cơ bản nó đã xác nhận đề xuất của bạn. – JDB

1

Họ làm những việc khác nhau. Chúng biên dịch thành mã MSIL khác nhau, nhưng trong hầu hết các trường hợp, chúng có thể sẽ có cùng kết quả.

ToString là phương thức được xác định bởi Object, là loại cơ sở vốn có cho tất cả các đối tượng. Theo mặc định, nó trả về tên kiểu của đối tượng, nhưng nó có thể (và thường được) ghi đè bởi mỗi loại để nó trả về một chuỗi có ý nghĩa hơn. Ví dụ: trong ví dụ của bạn, x là đối tượng Int32Int32 ghi đè ToString để trả về "3" thay vì "System.Int32" mặc định.

Tôi không tích cực, nhưng tôi nghi ngờ khi bạn thực hiện nối "" & x, nó được đúc x đến một String, trong trường hợp này nó là một phím tắt để gõ "" & CType(x, String) hoặc "" & CStr(x). Mỗi loại có thể quá tải các nhà điều hành đúc, do đó, nó giả định rằng loại (trong trường hợp này Int32) đã quá tải các nhà điều hành và do đó có thể được đúc thành một chuỗi. Thật vậy nó có và có thể.

Convert.ToString thực hiện những việc khác nhau tùy thuộc vào tình trạng quá tải bạn gọi. Nếu bạn vượt qua nó Int32, nó chỉ cần gọi phương thức ToString() của đối tượng. Tuy nhiên, nếu bạn vượt qua nó Object, ví dụ, trước tiên nó sẽ kiểm tra xem đối tượng có thực hiện IConvertible hoặc IFormattable hay không. Nếu có, nó sử dụng một trong số đó, nếu không nó sẽ sử dụng phương thức ToString. Vì vậy, nó cố gắng, tùy thuộc vào loại đối tượng bạn gửi nó, để xác định những gì nó nghĩ rằng nó là cách tốt nhất có khả năng nhất để có được loại đó vào một chuỗi. Theo như phương pháp ưa thích, tôi sẽ nói x.ToString() là những gì bạn muốn sử dụng hầu hết mọi lúc, trừ khi bạn có một số mối quan tâm khác (tất cả phụ thuộc vào những gì bạn đang làm với đối tượng).

+0

Tôi đã phát hiện ra rằng CStr (DBNull.Value) sẽ gây ra một InvalidCastException, nhưng "" & DBNull.Value sẽ không. Vì vậy, tôi không nghĩ rằng nó được đúc đối tượng để nhập chuỗi. Nhưng, "" & Không có gì cũng hoạt động, vì vậy tôi không nghĩ rằng nó nhất thiết phải gọi ToString(). – JDB

+0

Cảm ơn bạn đã chỉ ra các khả năng nâng cao của Convert.ToString - đã không nhận ra nó đã làm tất cả điều đó. Sự phản ánh thêm làm chậm chức năng xuống một chút so với gọi ToString(), nhưng sự khác biệt (xem câu trả lời của tôi dưới đây) là không đáng kể. – JDB

1

Tôi quyết định kiểm tra hiệu suất của từng phương pháp bằng cách sử dụng bộ sưu tập 1.000.000 đối tượng. Các đối tượng là một trong số: một số nguyên, một lớp, Không có gì hoặc DBNull.Value. Cùng một bộ sưu tập đã được sử dụng cho mỗi bài kiểm tra, và tôi đã kiểm tra từng phương pháp 50 lần.

"" & x
Điều này thực sự không hiệu quả với tất cả các đối tượng. Nó hoạt động cho DBNull.Value và Nothing, nhưng cố gắng sử dụng phương thức này chỉ với bất kỳ đối tượng ol 'nào sẽ gây ra một InvalidCastException. Thật thú vị, CStr (DBNull.Value) ném một InvalidCastException, vì vậy tôi không chắc chắn tại sao nó hoạt động.

Kết quả với đối tượng tùy chỉnh: N/A
Kết quả w/o đối tượng tùy chỉnh: avg 126,7 ms, trung bình 126 ms

If(x, "").ToString()
Kết quả với đối tượng tùy chỉnh: avg 140,46 ms, trung bình 138 ms
Kết quả w/o đối tượng tùy chỉnh: avg 69.32 ms, trung bình 69 ms

Convert.ToString()
Kết quả với đối tượng tùy chỉnh: avg 171,54 ms, trung bình 171 ms
Kết quả w/o đối tượng tùy chỉnh: avg 112,14 ms, trung bình 112 ms

Vì vậy, có vẻ như là If(x, "").ToString() nhanh hơn một chút đối với một tập hợp rất lớn các bản ghi, nhưng điều đó sẽ cần phải được cân bằng với nhiều hơn p2e của Convert.ToString() tùy chọn chuyển đổi rful. Cảm ơn câu trả lời.

Dưới đây là đoạn code tôi dùng để thử nghiệm:

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 
Các vấn đề liên quan