2009-12-22 21 views
12

Vì vậy, tôi hiểu những gì boxing và unboxing là. Khi nào nó xuất hiện trong mã thực tế, hoặc trong những ví dụ nào đó là một vấn đề? Tôi không thể tưởng tượng làm điều gì đó giống như ví dụ này:Quyền anh và unboxing: khi nào nó xuất hiện?

int i = 123; 
object o = i;   // Boxing 
int j = (int)o;  // Unboxing 

... nhưng điều đó gần như chắc chắn cực kỳ đơn giản và tôi thậm chí có thể làm boxing/unboxing mà không biết trước.

+0

Tôi đồng ý với bạn. Từ tất cả những gì tôi đã đọc về chủ đề này, tôi không nhận được điểm. Phải thiếu một cái gì đó :) –

Trả lời

31

Đó là số nhiều ít hơn một vấn đề ngay bây giờ so với trước khi dùng thuốc generic. Bây giờ, ví dụ: chúng tôi có thể sử dụng:

List<int> x = new List<int>(); 
x.Add(10); 
int y = x[0]; 

Không cần đấm bốc hoặc unboxing.

Trước đây, chúng tôi đã có:

ArrayList x = new ArrayList(); 
x.Add(10); // Boxing 
int y = (int) x[0]; // Unboxing 

Đó là kinh nghiệm phổ biến nhất của tôi về boxing và unboxing, ít nhất.

Nếu không có generics tham gia, tôi nghĩ rằng tôi có thể nói rằng phản ánh là nguyên nhân phổ biến nhất của boxing trong các dự án tôi đã làm việc trên. Các API phản chiếu luôn sử dụng "đối tượng" cho những thứ như giá trị trả về cho một phương thức - bởi vì chúng không có cách nào khác để biết phải sử dụng cái gì.

Một nguyên nhân khác có thể bắt bạn nếu bạn không biết nó là nếu bạn sử dụng loại giá trị thực hiện giao diện và chuyển giá trị đó sang phương thức khác có loại giao diện làm tham số của nó. Một lần nữa, generics làm cho điều này ít hơn của một vấn đề, nhưng nó có thể là một bất ngờ khó chịu nếu bạn không nhận thức được nó.

+7

"Tôi nghĩ rằng tôi có thể nói rằng sự phản ánh là nguyên nhân phổ biến nhất của boxing trong các dự án tôi đã làm việc trên" - điều này, tất nhiên, sẽ phụ thuộc rất nhiều vào các loại dự án. Ví dụ, nếu bạn làm việc với WPF hoặc Silverlight, boxing sẽ xuất hiện * mọi lúc * khi bạn làm việc với các bộ chuyển đổi giá trị (IValueConverter lấy và trả về đối tượng), các thuộc tính phụ thuộc (DependencyObject.GetValue và SetValue trả về và lấy đối tượng), v.v. – itowlson

+0

1 Đối với giao diện được thực hiện trên một loại giá trị - đó là một cái lén lút :) –

+0

@ itowlson: Đó là những ví dụ tuyệt vời - hãy nhớ nếu tôi thêm chúng vào câu trả lời của tôi? –

8

Boxing (theo kinh nghiệm của tôi) thường xảy ra trong những trường hợp:

  • Một kiểu giá trị được chuyển cho một phương pháp mà chấp nhận một đối số kiểu Object.
  • Loại giá trị được thêm vào bộ sưu tập không chung chung (như ArrayList).

Lần khác bạn có thể thấy quyền anh và unboxing là khi bạn sử dụng phản chiếu làm API phản chiếu của khung công tác .NET làm cho việc sử dụng nhiều Object.

+1

Chúng ta cần lưu ý: int (Int32) là một lớp con của lớp trừu tượng ValueType, là một lớp con của Object. –

+0

Tôi sẽ không nói đó là "phân lớp" - nó không phải là một lớp * nào cả. Nó kế thừa từ (hoặc có nguồn gốc từ) 'ValueType'. Thông số C# và CLI sử dụng thuật ngữ hơi khác nhau ở mặt trước này, điều này không giúp ích gì. –

1

Quyền anh và unboxing thực sự chuyển từ loại giá trị sang loại tham chiếu. Vì vậy, hãy nghĩ về nó khi di chuyển từ ngăn xếp sang heap và ngược lại.

Chắc chắn có những trường hợp điều này có liên quan. Sự bao gồm của generics trong khuôn khổ 2.0 cắt rất nhiều trường hợp boxing phổ biến ra khỏi thực tế.

+0

C# 2, không phải là khuôn khổ 2.0;) – disklosr

0

Kể từ khi xuất hiện danh sách và từ điển mạnh mẽ bằng cách sử dụng Generics với C# 2.0 (Visual Studio 2005), tôi nghĩ tầm quan trọng của việc giữ boxing/unboxing trong tâm trí đã được giảm thiểu đáng kinh ngạc. Thêm vào đó các loại nullable (int?, vv) và sử dụng toán tử kết hợp null (??) và nó thực sự không phải là một mối quan tâm nhiều và có thể sẽ không nhìn thấy nó trong bất kỳ mã nào không phải là 1.1 Framework hoặc trước đó.

+2

Không, trong generics có rất nhiều boxing hơn xảy ra hơn hầu hết mọi người mong đợi. C# sẽ phát ra .box khi bạn kiểm tra Ts không bị cản trở đối với null. –

+0

Tôi đồng ý với điều đó - nhưng đó là quyết định của nhà phát triển khi thực hiện một phương pháp/lớp chung. Từ góc độ khung công tác, các bộ sưu tập chung cho phép người tiêu dùng bỏ qua kịch bản boxing/unboxing. Khi tôi viết kịch bản mà bạn mô tả, T không bị giới hạn của tôi sẽ được so sánh với mặc định (T), không phải là null. Nếu tôi * thực sự * cần một kiểm tra đối với null, T tốt hơn nên bị ràng buộc với một kiểu tham chiếu. –

+0

"trong bất kỳ mã nào không phải là 1.1 Khung hoặc trước đó" - những gì về một string.Format đơn giản ("Số của tôi là {0}", 123)? – Alex

4

Quyền anh/unboxing xảy ra khi loại giá trị (như cấu trúc, int, dài) được chuyển đến đâu đó chấp nhận loại tham chiếu - chẳng hạn như object.

Điều này xảy ra khi bạn rõ ràng tạo phương thức lấy thông số của đối tượng kiểu sẽ được chuyển qua loại giá trị. Nó cũng xuất hiện khi bạn sử dụng các bộ sưu tập không chung chung cũ hơn để lưu trữ các kiểu giá trị (thường là các kiểu nguyên thủy).

Bạn cũng sẽ thấy boxing xảy ra khi bạn sử dụng String.Format() và chuyển nguyên thủy cho nó. Điều này là do String.Format() chấp nhận một đối tượng params [] - kết quả trong việc đánh thức các tham số bổ sung trong cuộc gọi. Sử dụng phản xạ để gọi các phương thức cũng có thể dẫn đến boxing/unboxing, vì các API phản chiếu không có lựa chọn nào khác ngoài việc trả về object vì loại thực không được biết tại thời gian biên dịch (và các API phản chiếu không thể là chung).

Các bộ sưu tập chung mới hơn không dẫn đến đánh boxing/unboxing, và do đó, thích hợp hơn với các bộ sưu tập cũ hơn vì lý do này (ví dụ: ArrayList, Hashtable, v.v.). Chưa kể chúng là an toàn.

Bạn có thể tránh các mối quan tâm quyền anh bằng cách thay đổi các phương thức chấp nhận các đối tượng chung chung. Ví dụ:

public void string Decorate(object a) // passing a value type results in boxing 
{ 
    return a.ToString() + " Some other value"; 
} 

vs:

public void string Decorate<T>(T a) 
{ 
    return a.ToString() + " some other value"; 
} 
1

Nó xảy ra mọi lúc khi người ta không biết những gì ý nghĩa là, chỉ đơn giản là không quan tâm hoặc đôi khi người ta không thể không chấp nhận quyền Anh là ít evel.

Loại dữ liệu được nhập mạnh sẽ hộp/bỏ hộp khá nhiều khi bạn truy cập thuộc tính loại giá trị. Ngoài ra, việc sử dụng loại giá trị làm tham chiếu giao diện cũng sẽ được sắp xếp. Hoặc nhận được một đại biểu từ một phương pháp thể hiện của một loại giá trị. (Mục tiêu của đại biểu là loại Object)

3

Đây là một thực sự khó chịu một :)

SqlCommand cmd = <a command that returns a scalar value stored as int>; 

// This code works very well. 
int result = (int)cmd.ExecuteScalar(); 

// This code will throw an exception. 
uint result = (uint)cmd.ExecuteScalar(); 

Thứ hai thực hiện không thành công vì nó cố gắng Unbox một Int32 thành một UInt32 mà là không thể. Vì vậy, bạn phải unbox đầu tiên và hơn cast.

uint result = (uint)(int)cmd.ExecuteScalar(); 
+0

+1 để cung cấp ví dụ – chikak

Các vấn đề liên quan