2009-07-06 27 views
59

Tôi có một IDataRecord reader rằng tôi lấy một chữ số thập phân từ như sau:Tại sao tôi không thể bỏ chọn một int dưới dạng số thập phân?

decimal d = (decimal)reader[0]; 

Đối với một số lý do này ném một ngoại lệ cast không hợp lệ nói rằng "diễn viên chỉ định không hợp lệ."

Khi tôi làm reader[0].GetType() nó cho tôi biết rằng đó là Int32. Theo như tôi biết, đây không phải là vấn đề ....

Tôi đã thử nghiệm điều này bằng đoạn trích này hoạt động tốt.

int i = 3750; 
decimal d = (decimal)i; 

Điều này đã khiến tôi gãi đầu tự hỏi tại sao không thể bỏ hộp int chứa trong trình đọc dưới dạng thập phân.

Có ai biết tại sao điều này có thể xảy ra không? Có cái gì đó tinh tế tôi đang thiếu?

Trả lời

74

Bạn chỉ có thể bỏ chọn loại giá trị thành loại ban đầu của nó (và phiên bản có thể vô hiệu của loại đó).

Bằng cách này, đây là hợp lệ (chỉ là một viết tắt cho phiên bản hai dòng của bạn):

object i = 4; 
decimal d = (decimal)(int)i; // works even w/o decimal as it's a widening conversion 

Đối với lý do đằng sau này đọc Eric Lippert's blog entry: Representation and Identity

Cá nhân, tôi phân loại những điều thực hiện bởi cú pháp đúc thành bốn loại hoạt động khác nhau (tất cả đều có các hướng dẫn IL khác nhau):

  1. Boxing (box hướng dẫn IL) và unboxing ()IL hướng dẫn)
  2. Đúc thông qua hệ thống phân cấp inhertiance (như dynamic_cast<Type> trong C++, sử dụng castclass IL hướng dẫn để xác minh)
  3. Đúc giữa các loại nguyên thủy (như static_cast<Type> trong C++, có rất nhiều hướng dẫn IL với nhiều loại khác nhau của phôi giữa các kiểu nguyên thủy)
  4. Gọi các toán tử chuyển đổi do người dùng xác định (ở cấp IL, chúng chỉ là các cuộc gọi phương thức đến phương thức thích hợp op_XXX).
+20

Trong một ý nghĩa, đó là một sự xấu hổ mà unboxing và đúc cú pháp trông giống hệt nhau, vì chúng là các hoạt động rất khác nhau. – jerryjvl

+0

Cảm ơn Mehrdad. Lời giải thích và liên kết của bạn với blog của Eric khá hữu ích. – mezoid

+0

Cảm ơn bạn! Điều này đã ném tôi cho một vòng lặp. – Darryl

14

Không có vấn đề gì trong việc đúc int đến decimal, nhưng khi bạn đang unboxing đối tượng, bạn phải sử dụng đúng loại đối tượng chứa.

Để Unbox giá trị int thành một giá trị decimal, trước tiên bạn Unbox nó như một int, sau đó bỏ nó vào thập phân:

decimal d = (decimal)(int)reader[0]; 

Giao diện IDataRecord cũng có phương pháp để unboxing giá trị:

decimal d = (decimal)reader.GetInt32(0); 
+0

Cảm ơn bạn đã trả lời quá Guffa ... nó rất hữu ích. – mezoid

+0

Nhưng nếu giá trị đôi khi là một số đầy đủ nhưng lần khác là số thập phân thực. truyền đến int đầu tiên sẽ mất giá trị thập phân. Nếu bạn mong đợi một đôi sau đó MAKE chắc chắn bằng cách xác nhận rằng nguồn cung cấp cho bạn một dobule. Nếu không, bạn sẽ nhận được các tác dụng phụ sẽ khiến người dùng cuối gãi tóc và sau đó chọc vào nhãn cầu của bạn. Câu trả lời hay nhưng rất xấu - Nó xứng đáng là -1 – ppumkin

+1

@ppumkin: Xin lỗi nếu bạn hiểu sai câu trả lời. Nó không được đúc thành 'int' và sau đó là' decimal', nó là * unboxing * một 'int' và sau đó đúc thành' decimal'. Unboxing giá trị là 'int' sẽ không bao giờ làm cho nó mất bất cứ thứ gì cả, bởi vì nó không thể unbox nó như là một' int' nếu nó không thực sự là một 'int' để bắt đầu với. – Guffa

3

Mehrdad Afshari cho biết:

Bạn chỉ có thể Unbox một giá trị ty pe cho loại ban đầu của nó (và phiên bản có giá trị có thể vô hiệu).

Điều cần nhận thấy là có sự khác biệt giữa cách đúc và unboxing. jerryjvl có một nhận xét tuyệt vời

Trong một ý nghĩa, đó là một sự xấu hổ mà unboxing và đúc cú pháp trông giống hệt nhau, vì chúng là các hoạt động rất khác nhau.

Đúc:

int i = 3750; // Declares a normal int 
decimal d = (decimal)i; // Casts an int into a decimal > OK 

Boxing/Unboxing:

object i = 3750; // Boxes an int ("3750" is similar to "(int)3750") 
decimal d = (decimal)i; // Unboxes the boxed int into a decimal > KO, can only unbox it into a int or int? 
12

Đây là một giải pháp đơn giản. Nó sẽ chăm sóc unboxing và sau đó đúc sang thập phân. Làm việc tốt cho tôi.

decimal d = Convert.ToDecimal(reader[0]); // reader[0] is int 
Các vấn đề liên quan