Bunu anlamanın en iyi yolu, C #'ın üzerine inşa ettiği alt düzey programlama dillerine bakmaktır.
C gibi en alt düzey dillerde, tüm değişkenler tek bir yere gider: Yığın. Bir değişkeni her bildirdiğinizde, Yığına gider. Bunlar yalnızca bir bool, bayt, 32 bit int, 32 bit uint, vb. Gibi ilkel değerler olabilir. Yığın hem basit hem de hızlıdır. Değişkenler eklendikçe sadece bir diğerinin üstüne giderler, bu yüzden ilk bildirdiğinizde 0x00, diğeri 0x01'de, diğeri RAM'de 0x02'de vb. Oturur. Ayrıca, değişkenler genellikle derleme Böylece programı çalıştırmadan önce adresleri bilinir.
Bir sonraki aşamada, C ++ gibi, Yığın adı verilen ikinci bir bellek yapısı tanıtılır. Hala yığın içinde yaşıyorsanız, ancak bir nesnenin ilk baytı için bellek adresini depolayan ve nesnenin yığın içinde yaşadığı Pointers adı verilen özel ints eklenebilir. Yığın bir tür karışıklık ve bakımı biraz pahalı, çünkü Yığın değişkenlerinin aksine, bir program yürütülürken doğrusal olarak yukarı ve aşağı yığılmazlar. Belirli bir sırayla gelip gidebilirler ve büyüyebilir ve küçülebilirler.
İşaretçilerle uğraşmak zordur. Bunlar bellek sızıntılarının, arabellek taşmalarının ve hayal kırıklığının sebebidir. Kurtarmaya C #.
Daha yüksek bir düzeyde, C #, işaretçileri düşünmenize gerek yoktur - .Net çerçevesi (C ++ ile yazılmış) bunları sizin için düşünür ve bunları Nesnelere Referanslar olarak sunar ve performans için daha basit değerleri saklamanızı sağlar Değer Türleri olarak bools, bayt ve ints gibi. Kaputun altında, bir Sınıfı başlatan nesneler ve şeyler pahalı, Bellek Yönetimli Yığın'a giderken, Değer Türleri düşük seviyeli C - süper hızlı olan aynı Yığına girer.
Bu iki temel bellek kavramı (ve depolama stratejileri) arasındaki etkileşimi bir kodlayıcının bakış açısından basit tutmak adına, Değer Türleri herhangi bir zamanda Bokslanabilir. Boks, değerin Yığından kopyalanmasına, bir Nesneye konmasına ve Yığın üzerine yerleştirilmesine neden olur - daha pahalı, ancak Referans dünyası ile akışkan etkileşimi. Diğer cevapların işaret ettiği gibi, örneğin şunları söylediğinizde bu gerçekleşir:
bool b = false; // Cheap, on Stack
object o = b; // Legal, easy to code, but complex - Boxing!
bool b2 = (bool)o; // Unboxing!
Boksun avantajının güçlü bir örneği null için bir kontroldür:
if (b == null) // Will not compile - bools can't be null
if (o == null) // Will compile and always return false
Nesnemiz o teknik olarak Yığındaki, B yığınımızın Yığına kopyalanan bir kopyasına işaret eden bir adrestir. Bo, kutulu ve oraya konduğu için null değerini kontrol edebiliriz.
Genel olarak, boksa ihtiyacınız yoksa, örneğin bir argümana bir nesne olarak int / bool / herhangi bir şey iletmekten kaçınmalısınız. .Net'te Değer Türlerini nesne olarak geçirmeyi talep eden bazı temel yapılar vardır (ve bu nedenle Boks gerektirir), ancak çoğu zaman asla Box'a ihtiyacınız yoktur.
Kaçınmanız gereken Boks gerektiren tarihsel C # yapılarının kapsamlı olmayan bir listesi:
Etkinlik sistemi , saf kullanımda bir Yarış Koşulu olduğu ortaya çıkar ve zaman uyumsuzluğu desteklemez. Boks problemini ekleyin ve muhtemelen bundan kaçınılmalıdır. (Örneğin Generics kullanan bir zaman uyumsuz olay sistemiyle değiştirebilirsiniz.)
Eski Diş Açma ve Zamanlayıcı modelleri, parametreleri üzerinde bir Kutu zorladı, ancak daha temiz ve daha verimli olan async / await ile değiştirildi.
Net 1.1 Koleksiyonlar tamamen Boks'a dayanıyordu çünkü Generics'ten önce geldiler. Bunlar hala System.Collections'da tekmeliyor. Herhangi bir yeni kodda Bokstan kaçınmanın yanı sıra size daha güçlü tip güvenliği de sağlayan System.Collections.Generic Koleksiyonlarını kullanmalısınız .
Boksu zorlayan yukarıdaki tarihsel problemlerle uğraşmak zorunda kalmadıkça ve daha sonra Boxed olacağını bildiğinizde daha sonra Boxing'in performans isabetinden kaçınmak istemiyorsanız, Değer Türlerinizi nesne olarak beyan etmekten veya geçmekten kaçınmalısınız.
Mikael'in aşağıdaki önerisine göre:
Bunu yap
using System.Collections.Generic;
var employeeCount = 5;
var list = new List<int>(10);
Bu değil
using System.Collections;
Int32 employeeCount = 5;
var list = new ArrayList(10);
Güncelleme
Bu cevap aslında Int32, Bool vb. Önerdi, aslında Değer Türleri için basit takma adlar olduklarında boksa neden olur. Yani .Net, Bool, Int32, String ve C # gibi türlere sahiptir ve herhangi bir işlevsel fark olmadan bool, int, string için takma adlar kullanır.