Cách tốt nhất để hiểu điều này là xem xét các ngôn ngữ lập trình cấp thấp hơn mà C # xây dựng.
Trong các ngôn ngữ cấp thấp nhất như C, tất cả các biến đều đi một nơi: Ngăn xếp. Mỗi khi bạn khai báo một biến, nó sẽ xuất hiện trên Stack. Chúng chỉ có thể là các giá trị nguyên thủy, như bool, byte, int 32 bit, uint 32 bit, v.v ... Stack vừa đơn giản vừa nhanh. Khi các biến được thêm vào, chúng chỉ đi lên trên một biến khác, do đó, biến đầu tiên bạn khai báo là 0x00, tiếp theo là 0x01, tiếp theo là 0x02 trong RAM, v.v. Ngoài ra, các biến thường được xử lý trước khi biên dịch- thời gian, vì vậy địa chỉ của họ được biết trước khi bạn chạy chương trình.
Ở cấp độ tiếp theo, như C ++, cấu trúc bộ nhớ thứ hai được gọi là Heap được giới thiệu. Bạn vẫn chủ yếu sống trong Stack, nhưng ints đặc biệt gọi là Con trỏ có thể được thêm vào Stack, lưu địa chỉ bộ nhớ cho byte đầu tiên của Object và Object đó sống trong Heap. Heap là một mớ hỗn độn và hơi tốn kém để duy trì, bởi vì không giống như các biến Stack, chúng không chồng chất lên nhau và sau đó xuống khi chương trình thực thi. Chúng có thể đến và đi không theo trình tự cụ thể, và chúng có thể phát triển và co lại.
Đối phó với con trỏ là khó khăn. Chúng là nguyên nhân gây rò rỉ bộ nhớ, tràn bộ đệm và thất vọng. C # để giải cứu.
Ở cấp độ cao hơn, C #, bạn không cần phải suy nghĩ về con trỏ - khung .Net (viết bằng C ++) nghĩ về những điều này cho bạn và giới thiệu chúng với bạn dưới dạng Tham chiếu đến Đối tượng và để thực hiện, cho phép bạn lưu trữ các giá trị đơn giản hơn như bools, byte và ints là các loại giá trị. Bên dưới mui xe, các Đối tượng và nội dung bắt đầu một Lớp đi trên Heap được quản lý bộ nhớ đắt tiền, trong khi Các loại giá trị đi vào cùng một Stack mà bạn có ở cấp độ C - siêu nhanh.
Để giữ cho sự tương tác giữa hai khái niệm cơ bản khác nhau về bộ nhớ (và chiến lược lưu trữ) đơn giản theo quan điểm của người viết mã, Các loại giá trị có thể được đóng hộp bất cứ lúc nào. Quyền anh khiến giá trị được sao chép từ Stack, đặt vào Object và được đặt trên Heap - đắt hơn, nhưng tương tác trôi chảy với thế giới Tham chiếu. Như các câu trả lời khác chỉ ra, điều này sẽ xảy ra khi bạn nói ví dụ:
bool b = false; // Cheap, on Stack
object o = b; // Legal, easy to code, but complex - Boxing!
bool b2 = (bool)o; // Unboxing!
Một minh họa mạnh mẽ về lợi thế của Boxing là kiểm tra null:
if (b == null) // Will not compile - bools can't be null
if (o == null) // Will compile and always return false
Đối tượng o của chúng tôi về mặt kỹ thuật là một địa chỉ trong Stack chỉ đến một bản sao của bool b của chúng tôi, đã được sao chép vào Heap. Chúng tôi có thể kiểm tra o cho null vì bool đã được đóng hộp và đặt ở đó.
Nói chung, bạn nên tránh Boxing trừ khi bạn cần nó, ví dụ để truyền int / bool / bất cứ thứ gì làm đối tượng cho một đối số. Có một số cấu trúc cơ bản trong .Net vẫn yêu cầu chuyển Loại giá trị làm đối tượng (và do đó yêu cầu Quyền anh), nhưng đối với hầu hết các phần bạn không bao giờ cần phải đóng hộp.
Một danh sách không đầy đủ các cấu trúc C # lịch sử yêu cầu Quyền anh, mà bạn nên tránh:
Hệ thống Sự kiện hóa ra có Điều kiện Cuộc đua khi sử dụng nó một cách ngây thơ và nó không hỗ trợ async. Thêm vào vấn đề Boxing và có lẽ nên tránh. (Bạn có thể thay thế nó bằng hệ thống sự kiện không đồng bộ sử dụng Generics.)
Các mô hình Threading và Timer cũ buộc Box trên các tham số của chúng nhưng đã được thay thế bằng async / await, nó sạch hơn và hiệu quả hơn.
Bộ sưu tập .Net 1.1 hoàn toàn dựa vào Quyền anh, vì chúng xuất hiện trước Generics. Chúng vẫn đang được sử dụng trong System.Collections. Trong bất kỳ mã mới nào, bạn nên sử dụng Bộ sưu tập từ System.Collections.Generic, ngoài việc tránh Boxing còn cung cấp cho bạn loại an toàn mạnh hơn .
Bạn nên tránh khai báo hoặc chuyển Loại giá trị của mình dưới dạng đối tượng, trừ khi bạn phải giải quyết các vấn đề lịch sử nêu trên buộc Boxing và bạn muốn tránh hiệu năng của Boxing sau này khi bạn biết rằng dù sao nó cũng sẽ bị đóng hộp.
Theo gợi ý của Mikael dưới đây:
Làm cái này
using System.Collections.Generic;
var employeeCount = 5;
var list = new List<int>(10);
Không phải cái này
using System.Collections;
Int32 employeeCount = 5;
var list = new ArrayList(10);
Cập nhật
Câu trả lời này ban đầu đề xuất Int32, Bool, vv gây ra quyền anh, trong khi thực tế chúng là bí danh đơn giản cho các loại giá trị. Đó là, .Net có các loại như Bool, Int32, String và C # bí danh chúng thành bool, int, chuỗi, mà không có bất kỳ sự khác biệt về chức năng.