Double.TryParse hoặc Convert.ToDouble - cái nào nhanh hơn và an toàn hơn?


80

Ứng dụng của tôi đọc tệp Excel bằng VSTO và thêm dữ liệu đã đọc vào a StringDictionary. Nó chỉ thêm dữ liệu là các số có một vài chữ số (1000 1000,2 1000,34 - dấu phẩy là dấu phân cách theo tiêu chuẩn của Nga).

Điều gì tốt hơn là kiểm tra xem chuỗi hiện tại có phải là một số thích hợp không?

object data, string key; // data had read

try
{
  Convert.ToDouble(regionData, CultureInfo.CurrentCulture);
  dic.Add(key, regionData.ToString());
}
catch (InvalidCastException)
{
  // is not a number
}

hoặc là

double d;
string str = data.ToString();
if (Double.TryParse(str, out d)) // if done, then is a number
{
  dic.Add(key, str);
}

Tôi phải sử dụng StringDictionarythay Dictionary<string, double>vì vì các vấn đề thuật toán phân tích cú pháp sau đây.

Câu hỏi của tôi: Cách nào nhanh hơn? Cái nào an toàn hơn?

Và nó là tốt hơn để gọi Convert.ToDouble(object)hoặc Convert.ToDouble(string)?


FYI, double.TryParse giống như try {result = double.Parse (s); trả về true; } bắt {return false; }. Convert về cơ bản là một trình bao bọc cho cả hai với một loạt các quá tải. Nó không có sự khác biệt như thế nào bạn làm điều đó. Nhưng như Jon đã chỉ ra, hãy nghĩ về cách xử lý đầu vào không tốt.
John Leidegren

12
Double.TryParse không giống như double.Parse được gói trong một thử..catch. Ngữ nghĩa giống nhau, nhưng đường dẫn mã khác nhau. Đầu tiên TryParse xác minh rằng chuỗi là một số bằng cách sử dụng Number.TryStringToNumber nội bộ, trong khi Parse giả định rằng nó đã là một số / kép.
Jeff Moser

Câu trả lời:


131

Tôi đã thực hiện một bài kiểm tra nhanh phi khoa học ở chế độ Phát hành. Tôi đã sử dụng hai đầu vào: "2.34523" và "badinput" vào cả hai phương thức và lặp lại 1.000.000 lần.

Đầu vào hợp lệ:

Double.TryParse = 646ms
Convert.ToDouble = 662 ms

Không khác nhiều, như mong đợi. Đối với tất cả các ý định và mục đích, đối với đầu vào hợp lệ, chúng đều giống nhau.

Đâu vao không hợp lệ:

Double.TryParse = 612ms
Convert.ToDouble = ..

Chà .. nó đã chạy trong một thời gian dài. Tôi làm lại toàn bộ nội dung bằng cách sử dụng 1.000 lần lặp và Convert.ToDoublevới đầu vào không tốt mất 8,3 giây. Tính trung bình nó sẽ mất hơn 2 giờ. Tôi không quan tâm việc kiểm tra cơ bản như thế nào, trong trường hợp đầu vào không hợp lệ, Convert.ToDoubleviệc nâng cao ngoại lệ sẽ làm hỏng hiệu suất của bạn.

Vì vậy, đây là một phiếu bầu khác cho TryParsemột số con số để sao lưu nó.


4
Ngoài những điều đã đề cập ở trên, tôi chỉ thấy rằng Convert.ToDouble () sẽ ném một ngoại lệ với các số trong ký hiệu khoa học. Hãy xem xét điều này: double toDouble = Convert.ToDouble ((- 1/30000) .ToString ()); // sẽ bị lỗi double dblParse = Double.Parse ((- 1/30000) .ToString ()); // hoạt động tốt
Buddy Lee

46

Để bắt đầu, tôi muốn sử dụng double.Parsehơn là Convert.ToDoublengay từ đầu.

Về việc liệu bạn có nên sử dụng Parsehoặc TryParse: bạn có thể tiếp tục nếu có dữ liệu đầu vào không tốt, hoặc đó là một điều kiện thực sự đặc biệt? Nếu nó đặc biệt, hãy sử dụng Parsevà để nó nổ tung nếu đầu vào kém. Nếu nó được mong đợi và có thể được xử lý sạch sẽ, hãy sử dụng TryParse.


6
Jon, Bạn có thể giải thích tại sao bạn thích double.Parse hơn Convert.ToDouble không?
David North

10
@dnorthut: Về cơ bản, tôi hiếm khi muốn null được chuyển đổi thành 0 (mà Convert.ToDouble làm được). Nó cũng thường linh hoạt hơn. Tôi chỉ có xu hướng đi tìm các phương pháp cụ thể ...
Jon Skeet

8

Nguyên tắc thiết kế .NET Framework khuyên bạn nên sử dụng các phương pháp Thử. Tránh ngoại lệ thường là một ý kiến ​​hay.

Convert.ToDouble(object) sẽ làm ((IConvertible) object).ToDouble(null);

Cái nào sẽ gọi Convert.ToDouble(string, null)

Vì vậy, sẽ nhanh hơn để gọi phiên bản chuỗi.

Tuy nhiên, phiên bản chuỗi chỉ thực hiện điều này:

if (value == null)
{
    return 0.0;
}
return double.Parse(value, NumberStyles.Float | NumberStyles.AllowThousands, provider);

Vì vậy, việc làm double.Parsetrực tiếp sẽ nhanh hơn .


7

Nếu bạn không xử lý ngoại lệ, hãy sử dụng TryParse. TryParse nhanh hơn vì nó không phải xử lý toàn bộ dấu vết ngăn xếp ngoại lệ.


7

Nói chung, tôi cố gắng tránh Convertlớp (nghĩa là: Tôi không sử dụng nó) vì tôi thấy nó rất khó hiểu: mã cung cấp quá ít gợi ý về những gì chính xác xảy ra ở đây vì Convertcho phép nhiều chuyển đổi rất khác nhau về ngữ nghĩa xảy ra với cùng một mã . Điều này làm cho lập trình viên khó kiểm soát chính xác những gì đang xảy ra.

Lời khuyên của tôi, do đó, là không bao giờ sử dụng lớp này. Nó cũng không thực sự cần thiết (ngoại trừ định dạng nhị phân của một số, vì ToStringphương thức bình thường của các lớp số không cung cấp một phương thức thích hợp để thực hiện điều này).


7

Trừ khi bạn chắc chắn 100% thông tin đầu vào của mình, trường hợp này hiếm khi xảy ra, bạn nên sử dụng Double.TryParse.

Convert.ToDouble will throw an exception on non-numbers
Double.Parse will throw an exception on non-numbers or null
Double.TryParse will return false or 0 on any of the above without generating an exception.

Tốc độ phân tích cú pháp sẽ trở thành thứ yếu khi bạn ném một ngoại lệ vì không chậm hơn nhiều so với một ngoại lệ.


4

Rất nhiều người ghét lớp Convert ở đây ... Chỉ cần cân bằng một chút, có một lợi thế cho Convert - nếu bạn được giao một đồ vật,

Convert.ToDouble(o);

chỉ có thể trả về giá trị một cách dễ dàng nếu o đã là một Double (hoặc một int hoặc bất kỳ thứ gì có thể truyền dễ dàng).

Sử dụng Double.Parse hoặc Double.TryParse là rất tốt nếu bạn đã có nó trong một chuỗi, nhưng

Double.Parse(o.ToString());

phải làm cho chuỗi được phân tích cú pháp trước và tùy thuộc vào đầu vào của bạn mà có thể đắt hơn.


1
+1: tôi thấy quan điểm của bạn, phân tích cú pháp các số / chuỗi đóng hộp với số bên trong System.Object khá dễ dàng, thay vào đó là một kiểm tra kiểu lớn. Nhưng về cơ bản tôi đồng ý với câu trả lời khác: Convert.ToSomething()là quá nhiều tốn kém hơn là Parse / TryParse, đặc biệt là trong bối cảnh lặp
T-moty

Đối với tôi, Convert.ToDouble (o) có một số điểm dễ dàng nếu những gì trong hộp đã là một con số, nhưng kẻ giết người thực sự đối với Convert là nó không có .TryToDouble (o, out d); Với mức độ đắt đỏ của các trường hợp ngoại lệ (và mức độ tin cậy của bạn - hay không - đối với các yếu tố đầu vào), đó là chi phí bổ sung lớn của Convert.
user1664043 22/09/15

2

Double.TryParse IMO.

Bạn sẽ dễ dàng xử lý hơn, Bạn sẽ biết chính xác nơi xảy ra lỗi.

Sau đó, bạn có thể đối phó với nó như thế nào bạn thấy phù hợp nếu nó trả về false (tức là không thể chuyển đổi).


2

Tôi luôn ưu tiên sử dụng các TryParse()phương pháp này vì nó sẽ giúp chuyển đổi thành công hay thất bại mà không phải lo lắng về các trường hợp ngoại lệ.


2

Đây là một câu hỏi cũ thú vị. Tôi đang thêm một câu trả lời vì không ai nhận thấy một vài điều với câu hỏi ban đầu.

Cái nào nhanh hơn: Convert.ToDouble hay Double.TryParse? Cái nào an toàn hơn: Convert.ToDouble hoặc Double.TryParse?

Tôi sẽ trả lời cả hai câu hỏi này (tôi sẽ cập nhật câu trả lời sau), chi tiết, nhưng trước tiên:

Để đảm bảo an toàn, điều mà mọi lập trình viên bỏ lỡ trong câu hỏi này là dòng (tôi nhấn mạnh):

Nó chỉ thêm dữ liệu là các số có một vài chữ số (1000 1000,2 1000,34 - dấu phẩy là dấu phân cách theo tiêu chuẩn của Nga ).

Tiếp theo là ví dụ mã này:

Convert.ToDouble(regionData, CultureInfo.CurrentCulture);

Điều thú vị ở đây là nếu bảng tính ở định dạng số Nga nhưng Excel không nhập chính xác các trường ô, thì cách giải thích chính xác các giá trị đến từ Excel là gì?

Đây là một điều thú vị khác về hai ví dụ, liên quan đến tốc độ:

catch (InvalidCastException)
{
    // is not a number
}

Điều này có thể sẽ tạo MSIL trông giống như sau:

catch [mscorlib]System.InvalidCastException 
{
  IL_0023:  stloc.0
  IL_0024:  nop
  IL_0025:  ldloc.0
  IL_0026:  nop
  IL_002b:  nop
  IL_002c:  nop
  IL_002d:  leave.s    IL_002f
}  // end handler
IL_002f: nop
IL_0030: return

Theo nghĩa này, chúng ta có thể so sánh tổng số hướng dẫn MSIL được thực hiện bởi mỗi chương trình - nhiều hơn về điều đó sau khi tôi cập nhật bài đăng này.

Tôi tin rằng mã phải chính xác, rõ ràng và nhanh chóng ... Theo thứ tự đó!


1

Cá nhân tôi thấy TryParsephương pháp này dễ đọc hơn, phương pháp nào bạn sẽ thực sự muốn sử dụng tùy thuộc vào trường hợp sử dụng của bạn: nếu lỗi có thể được xử lý cục bộ, bạn đang mong đợi lỗi và lợi nhuận TryParselà tốt, nếu không, bạn có thể muốn các trường hợp ngoại lệ bay.

Tôi hy vọng TryParsequá trình cũng sẽ nhanh hơn, vì nó tránh được chi phí xử lý ngoại lệ. Nhưng hãy sử dụng một công cụ điểm chuẩn, như MiniBench của Jon Skeet để so sánh các khả năng khác nhau.


Phản hồi về câu trả lời này: Nếu câu hỏi hỏi điều gì nhanh hơn và an toàn hơn, câu trả lời không nên bắt đầu bằng: "Cá nhân" và bao gồm phỏng đoán như: "Tôi mong đợi ...". Đây chỉ là suy nghĩ cá nhân và bình luận, không phải là một câu trả lời hay.
PandaWood
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.