C # 'da başvuru türü ile değer türü arasındaki fark nedir?


100

Birkaç ay önce bir adam bana bu soruyu sordu ve ben ayrıntılı olarak açıklayamadım. C # 'da başvuru türü ile değer türü arasındaki fark nedir?

O değer türleridir biliyorum int, bool, float, vb ve referans tipleridir delegate, interfacevb Ya da çok, bu yanlış mı?

Bunu bana profesyonel bir şekilde açıklayabilir misin?


3
Küçük bir not olarak, sorunun C # hakkında sorulduğunu düşünüyorum, ancak gerçekte C # + .NET ile ilgili. NET çözümlemeden C # çözümleyemezsiniz. Soruyu yeniden etiketlemeyeceğim çünkü birini analiz etmeden diğerini analiz ederken yapılması gereken bazı noktalar olabilir (yineleyiciler ve kapanışlar, sana bakıyorum)
xanatos

@xanatos en uygun şekilde C #, VB.Net ve Net'in hepsinin ortak olduğu CLI hakkında bir sorudur. CLI için bir etiket olmalıdır, ancak CLI başka bir şey için alınır. CLR var ama bu bir uygulama, standart değil.
user34660

Yanıtlar:


172

Sizin örnekler nedeniyle süre biraz garip int, boolve floatbelirli bir türünü arayüzleri ve yetki devri vardır vardır türlü Çeşidi - tıpkı structve enumdeğer türleri çeşitleri bulunmaktadır.

Bu makalede referans türleri ve değer türleri hakkında bir açıklama yazdım . Kafa karıştırıcı bulduğunuz her şeyi genişletmekten mutluluk duyarım.

"TL; DR" versiyonu, belirli bir tipteki bir değişkenin / ifadenin değerinin ne olduğunu düşünmektir. Bir değer türü için değer bilginin kendisidir. Bir referans tipi için değer, boş olabilen veya bilgiyi içeren bir nesneye gitmenin bir yolu olabilen bir referanstır.

Örneğin, bir değişkeni bir kağıt parçası gibi düşünün. Üzerinde "5" veya "yanlış" değeri yazabilirdi, ama benim evime sahip olamazdı ... evime yol tarifi olması gerekirdi . Bu talimatlar bir referansa eşdeğerdir. Özellikle, iki kişi evime aynı yönleri içeren farklı kağıt parçalarına sahip olabilirdi ve eğer bir kişi bu talimatları izler ve evimi kırmızıya boyarsa, o zaman ikinci kişi de bu değişikliği görürdü. Her ikisinin de kağıt üzerinde evimin ayrı resimleri olsaydı , o zaman bir kişi kağıdını boyamak diğer kişinin kağıdını hiç değiştirmezdi.


2
Bir şeyin sunabileceği üç farklı temel anlambilim türü olduğunu unutmamak önemlidir: değişmez anlambilim, değişken değer semantiği ve değişebilir referans semantiği. Kavramsal olarak, bir şeyin uyguladığı anlambilim türü, bağımsız bir yığın nesnesi veya bir değişken / alan (yapı) olarak depolanmasına göre ortogonaldir. Uygulamada, alanlarını açığa çıkarmayan yapılar herhangi bir anlambilim uygulayabilirken, .net'in yığın referanslarının rastgele paylaşılmasına izin vermesi, yığın nesnelerinin değişken değer semantiğini uygulayamayacağı anlamına gelir.
supercat

Bu kadarını alamadım - while int, bool and float are specific types, interfaces and delegates are kinds of type - just like struct and enum are kinds of value types. İnt ile neyi kastediyorsunuz, bool belirli türler mi? C # 'teki her şey örneğin int, bool, float, class, interface, delegate bir türdür (veri türü kesin olmalıdır). Veri türleri, C # 'da' Referans Türü 've' Değer Türü 'olarak ayrılmıştır. Öyleyse neden int'in belirli bir tür olduğunu , ancak arabirimin bir tür olduğunu söylüyorsunuz ?
RBT

2
@RBT: Veri türleri yalnızca "başvuru türü" ve "değer türü" olarak ayrılmaz . Ayrıca "sınıf, yapı, numaralandırma, temsilci, arabirim" olarak da ayrılırlar. intbir yapıdır, stringbir sınıftır, Actionbir temsilcidir, vb. "int, bool, float, sınıf, arabirim, temsilci" listeniz, "10, int" ile aynı şekilde, farklı türde şeyler içeren bir listedir. farklı türden şeyler içeren bir liste.
Jon Skeet

@JonSkeet Muhtemelen üzerinde cevabı bu yazı biraz sonra yanıltıcıdır.
RBT

@RBT: Biraz kötü ifade edildiğini söyleyebilirim, ama korkunç değil.
Jon Skeet

26

Değer türü:

Hafıza adreslerini değil bazı değerleri tutar

Misal:

Struct

Depolama:

TL; DR : Bir değişkenin değeri, kaldırıldığı her yerde saklanır. Örneğin yerel değişkenler yığın üzerinde yaşarlar, ancak bir sınıf içinde bir üye olarak bildirildiklerinde, içinde bildirildiği sınıfla sıkı bir şekilde birleştirilen yığın üzerinde yaşarlar.
Daha uzun : Böylece, bildirildikleri her yerde değer türleri depolanır. Örneğin: bir intyerel değişken olarak bir işlevin içindeki değeri yığın üzerinde saklanırken, intbir sınıftaki üye olarak bildirilen bir in değeri, içinde bildirildiği sınıfla birlikte yığın üzerinde depolanır. Bir değer türü bir sınıf, bildirildiği sınıfla tam olarak aynı olan ve çöp toplayıcının neredeyse hiç çalışmasını gerektirmeyen bir yaşam türüne sahiptir. Yine de daha karmaşık, @ JonSkeet'in " C # In Depth " kitabına atıfta bulunacağımDaha kısa bir açıklama için .NET'te Bellek ".

Avantajlar:

Bir değer türünün fazladan çöp toplamaya ihtiyacı yoktur. İçinde yaşadığı örnekle birlikte çöpleri toplar. Yöntemlerdeki yerel değişkenler, yöntem ayrıldıktan sonra temizlenir.

Dezavantajlar:

  1. Bir yönteme büyük değerler kümesi aktarıldığında, alıcı değişken gerçekte kopyalar, bu nedenle bellekte iki artık değer vardır.

  2. Sınıflar atlandıkça, tüm oop faydalarını kaybediyor

Başvuru türü:

Değer olmayan bir değerin hafıza adresini tutar

Misal:

Sınıf

Depolama:

Yığın üzerinde depolandı

Avantajlar:

  1. Bir referans değişkenini bir yönteme ilettiğinizde ve gerçekten orijinal değeri değiştirdiğinde, değer türlerinde verilen değişkenin bir kopyası alınır ve bu değer değiştirilir.

  2. Değişkenin boyutu daha büyük olduğunda referans türü iyidir

  3. Sınıflar referans türü değişkenler olarak geldikçe, yeniden kullanılabilirlik sağlarlar, böylece Nesne yönelimli programlamadan yararlanırlar

Dezavantajlar:

Değeri okurken ayırırken ve referansları kaldırırken daha fazla iş referansı. Çöp toplayıcı için ekstra aşırı yükleme


5
Başvuru türlerinin yığında depolanması ve değer türlerinin yığında depolanması doğru değildir. Daha fazla bilgi edinmek istiyorsanız yoda.arachsys.com/csharp/memory.html'yi okuyun .
Rhys

1
Bu cevapta pek çok yanlış anlama var. Lütfen Jeff Richters CLR'yi C # aracılığıyla okuyun. Değer Türleri, İş Parçacığı Yığınında depolanır ve çöp toplamaya (GC) tabi değildir - bunların GC ile hiçbir ilgisi yoktur. Referans Türleri, yönetilen yığında depolanır ve bu nedenle GC'ye tabidir. Bir Referans Türü bir kök referansına sahipse, toplanamaz ve 0, 1 ve 2. nesillere yükseltilir. Bir kök referansı yoksa, Çöp Toplanabilir ve daha sonra Diriliş adı verilen bu işlemden geçer. öldürülür ve hayata döndürülür ve sonunda toplanır.
Jeremy Thompson

13

Bilgisayarın nesneleri nasıl ayırdığını ve bir işaretçinin ne olduğunu bilirseniz, ikisinin farkını anlamayı daha kolay buldum.

Başvuru genellikle bir işaretçi ile ilişkilendirilir. Değişkeninizin bulunduğu hafıza adresi aslında gerçek nesnenin başka bir hafıza adresini farklı bir hafıza konumunda tutuyor demektir .

Benim vermek üzere olduğum örnek fazlasıyla basitleştirilmiş, bu yüzden biraz tuzla ele alalım.

Bilgisayar belleğinin, içinde bir şey tutabilen bir dizi PO kutusu olduğunu düşünün (PO Box 0001'den PO Box n'den başlayarak). Posta kutuları sizin için yapmazsa, bir hashtable veya sözlük veya bir dizi veya benzeri bir şey deneyin.

Böylece, şöyle bir şey yaptığınızda:

var a = "Merhaba";

bilgisayar şunları yapacaktır:

  1. bellek ayırın (5 bayt için 1000 bellek konumundan başlayarak) ve H (1000'de), e (1001'de), l (1002'de), l (1003'te) ve o (1004'te) koyun.
  2. bellekte bir yere ayırın (mesela 0500 konumunda) ve bunu a değişkeni olarak atayın.
    Yani bir tür takma ad gibi (0500 a'dır).
  3. bu bellek konumundaki (0500) değeri 1000'e atayın (bu, Hello dizesinin bellekte başladığı yerdir). Bu nedenle, a değişkeni , "Merhaba" dizgisinin gerçek başlangıç ​​bellek konumuna bir başvuru tutmaktadır .

Değer türü, gerçek şeyi bellek konumunda tutacaktır.

Böylece, şöyle bir şey yaptığınızda:

var a = 1;

bilgisayar şunları yapacaktır:

  1. 0500'de bir bellek konumu ayırın ve onu a değişkenine atayın (aynı takma ad)
  2. içine 1 değerini koyun (0500 hafıza konumuna).
    Gerçek değeri (1) tutmak için fazladan bellek ayırmadığımıza dikkat edin. Böylece a aslında gerçek değeri tutuyor ve bu yüzden buna değer türü deniyor.


@Jon, bu tür söylediklerimi geçersiz kılıyor, LOL. Ama dediğim gibi, benim durumumda yararlı bulduğum iki tür arasında biraz anlayış kazanmak büyük ölçüde basitleştirildi. En azından aklımda böyle hayal ettim :).
Jimmy Chandra

8

Bu, yaklaşık iki yıl önce farklı bir forumdaki bir yazımdan. Dil vb.net olsa da (C # yerine), Değer Türü ve Başvuru türü kavramları .net genelinde aynıdır ve örnekler hala geçerlidir.

.Net içinde TÜM türlerin teknik olarak Object temel türünden türediğini hatırlamak da önemlidir. Değer türleri, bu şekilde davranmak üzere tasarlanmıştır, ancak sonunda, temel nesne türünün işlevselliğini de miras alırlar.

A. Değer Tipleri sadece bellekte ayrı bir DEĞER'in depolandığı ayrı bir alanı temsil ederler. Değer türleri sabit bellek boyutundadır ve sabit boyutlu adreslerin bir koleksiyonu olan yığında saklanır.

Böyle bir açıklama yaptığınızda:

Dim A as Integer
DIm B as Integer

A = 3
B = A 

Aşağıdakileri yaptınız:

  1. 32 bitlik tam sayı değerlerini tutmaya yetecek kadar bellekte 2 boşluk oluşturuldu.
  2. A'ya atanan bellek tahsisine 3 değeri yerleştirildi
  3. A'da tutulan ile aynı değeri atayarak B'ye atanan bellek tahsisine 3 değeri yerleştirildi.

Her bir değişkenin Değeri, her bellek konumunda ayrı ayrı bulunur.

B. Referans Tipleri çeşitli boyutlarda olabilir. Bu nedenle, "Yığın" içinde depolanamazlar (unutmayın, yığın, sabit boyutta bellek ayırmalarının bir koleksiyonudur?). "Yönetilen Yığın" içinde depolanırlar. Yönetilen yığın üzerindeki her öğeye işaretçiler (veya "başvurular") yığında tutulur (Bir Adres gibi). Kodunuz, yönetilen yığında depolanan nesnelere erişmek için yığındaki bu işaretçileri kullanır. Dolayısıyla, kodunuz bir referans değişkeni kullandığında, aslında bir işaretçi (veya yönetilen yığın içindeki bir bellek konumuna "adres") kullanır.

Diyelim ki, bir Özellik Person.Name dizesine sahip clsPerson adında bir Sınıf oluşturduğunuzu varsayalım.

Bu durumda şöyle bir açıklama yaptığınızda:

Dim p1 As clsPerson
p1 = New clsPerson
p1.Name = "Jim Morrison"

Dim p2 As Person

p2 = p1

Yukarıdaki durumda, p1.Name Özelliği, beklediğiniz gibi "Jim Morrison" ı döndürür. P2.Name özelliği, sezgisel olarak beklediğiniz gibi "Jim Morrison" ı da döndürecektir. Hem p1 hem de p2'nin Yığın üzerinde farklı adresleri temsil ettiğine inanıyorum. Ancak artık p2'ye p1'in değerini atadığınıza göre, hem p1 hem de p2, yönetilen yığın üzerinde AYNI KONUMU gösterir.

Şimdi BU durumu düşünün:

Dim p1 As clsPerson
Dim p2 As clsPerson

p1 = New clsPerson
p1.Name = "Jim Morrison"

p2 = p1

p2.Name = "Janis Joplin"

Bu durumda, Nesneye referans veren Yığın üzerinde bir işaretçi p1 ile Yönetilen Yığın üzerindeki kişi Sınıfının yeni bir örneğini oluşturdunuz ve nesne örneğinin Ad Özelliğine yeniden "Jim Morrison" değeri atadınız. Daha sonra, Yığın içinde başka bir p2 gösterici yarattınız ve onu, p1 tarafından referans verilenle (p2 = p1 atamasını yaptığınızda) yönetilen yığın üzerinde aynı adrese işaret ettiniz.

İşte büküm geliyor. P2'nin Ad özelliğini "Janis Joplin" değerini atadığınızda, REFERENCED nesnesinin Ad özelliğini hem p1 hem de p2 tarafından değiştirirsiniz, öyle ki aşağıdaki kodu çalıştırırsanız:

MsgBox(P1.Name)
'Will return "Janis Joplin"

MsgBox(p2.Name)
'will ALSO return "Janis Joplin"Because both variables (Pointers on the Stack) reference the SAME OBJECT in memory (an Address on the Managed Heap). 

Bu mantıklı geldi mi?

Son. Eğer bunu yaparsan:

DIm p1 As New clsPerson
Dim p2 As New clsPerson

p1.Name = "Jim Morrison"
p2.Name = "Janis Joplin"

Artık iki farklı Kişi Nesneniz var. Ancak, BUNU tekrar yaptığınız anda:

p2 = p1

Şimdi ikisini de "Jim Morrison" a işaret ettiniz. (P2 tarafından atıfta bulunulan Yığın üzerindeki Nesneye ne olduğundan tam olarak emin değilim. Şimdi kapsam dışına çıktığını düşünüyorum. Bu, umarım birisinin beni düzeltebileceği alanlardan biri ...). -DÜZENLE: Yeni atamayı yapmadan önce p2 = Hiçbir şey VEYA p2 = Yeni clsPerson ayarlamanızın nedeninin bu olduğuna İNANIYORUM.

Bir kez daha, şimdi BUNU yaparsanız:

p2.Name = "Jimi Hendrix"

MsgBox(p1.Name)
MsgBox(p2.Name)

Her iki msgBoxes artık "Jimi Hendrix" döndürür

Bu biraz kafa karıştırıcı olabilir ve son bir kez söyleyeceğim, bazı detaylar yanlış olabilir.

İyi Şanslar ve umarım benden daha iyi bilenler bu konuyu açıklığa kavuşturmak için gelecektir. . .


Neden hiç olumlu oy almadınız bilmiyorum. İyi cevap, net, basit örneklerle anlamama yardımcı oldu.
Harry

Gelince Değer Türü Referans ya tip kavramların .net boyunca tekdüze, bunlar aslında Ortak Dil Altyapı tanımlanır (CLI) şartname, Ecma standart 335 (aynı zamanda bir ISO standardı). .Net'in standart kısmı için standart budur. Ecma standardı 334 (aynı zamanda bir ISO standardı) C # dilidir ve C # uygulamalarının ya CLI'ye dayanması ya da bu C # standardının gerektirdiği minimum CLI özelliklerini elde etmenin alternatif bir yolunu desteklemesi gerektiğini açıkça belirtir . Ancak VB.Net bir standart değildir, Microsoft'a özeldir.
user34660

5

değer veri türü ve referans veri türü

1) değer (verileri doğrudan içerir) ancak referans (veriyi ifade eder)

2) içinde değeri (her değişken kendi kopyası vardır) ama
içinde referans (daha değişken bazı nesnelere başvurabilirsiniz hariç)

3) değerde (işlem değişkeni diğer değişkeni etkileyemez ) ancak referansta (değişken diğerini etkileyebilir)

4) değer türleri (int, bool, float) ancak başvuru türü (dizi, sınıf nesneleri, dize)


2

Değer türü:

  • Sabit hafıza boyutu.

  • Yığın belleğinde saklanır.

  • Gerçek değeri tutar.

    Örn. int, char, bool vb.

Referans Türü:

  • Sabit hafıza değil.

  • Yığın hafızasında saklanır.

  • Gerçek değerin hafıza adresini tutar.

    Örn. dize, dizi, sınıf vb.


1

"Değer türlerine dayalı değişkenler doğrudan değerleri içerir. Bir değer türü değişkeninin diğerine atanması, içerilen değeri kopyalar. Bu, nesneye bir başvuruyu kopyalayan ancak nesnenin kendisine kopyalamayan başvuru türü değişkenlerinin atanmasından farklıdır." Microsoft'un kitaplığından.

Sen daha eksiksiz cevap bulabilirsiniz burada ve burada .


1
Bu açıklamadan hoşlanmıyorum çünkü atama, referans türleri ve değer türleri için farklı çalışıyor gibi görünüyor. Öyle değil. Her iki durumda da, "hedef" değişkenin değerini ifadeye eşit yapar - değer kopyalanır. Fark kopyalanır değer bir referanstır, referans tipleri için - yani değerinin ne olduğunu. Yine de değişkenin değeri budur.
Jon Skeet

Size katılıyorum ve bu makalede okuyabileceğiniz gibi farklı olabileceğini zaten biliyordum . Ancak, konuyla ilgili Microsoft'un kılavuzunu ve ayrıca genellikle kitaplarda nasıl okuduğunuzla ilgili tekrar gönderiyorum. Lütfen beni suçlama! :)
Lucas S.

Oh tabi ... arıza var MSDN belgelerin bit bol :) bulunacak vardır
Jon Skeet

1

Bazen açıklamalar özellikle yeni başlayanlar için yardımcı olmaz. Değer türünü veri dosyası olarak ve başvuru türünü bir dosyaya kısayol olarak hayal edebilirsiniz.

Dolayısıyla, bir referans değişkenini kopyalarsanız, yalnızca bağlantıyı / işaretçiyi bellekte herhangi bir yerdeki gerçek bir veriye kopyalarsınız. Bir değer türünü kopyalarsanız, hafızadaki verileri gerçekten klonlamış olursunuz.


0

Bu muhtemelen ezoterik yönden yanlıştır, ancak basitleştirmek gerekirse:

Değer türleri, normal olarak "değere göre" iletilen değerlerdir (bu nedenle kopyalanırlar). Referans türleri "referans olarak" aktarılır (bu nedenle, orijinal değere bir işaretçi verir). NET ECMA standardı tarafından bu "şeylerin" nereye kaydedileceğine dair herhangi bir garanti yoktur. Yığınsız veya yığınsız bir .NET uygulaması oluşturabilirsiniz (ikincisi çok karmaşık olabilir, ancak lifler ve birçok yığın kullanarak muhtemelen yapabilirsiniz)

Yapılar değer türüdür (int, bool ... yapılardır veya en azından ... olarak simüle edilirler), sınıflar başvuru türüdür.

Değer türleri System.ValueType'dan gelir. Başvuru türü System.Object öğesinden gelir.

Şimdi .. Sonunda, Değer Türü, "başvurulan nesneler" ve başvurular var (C ++ 'da nesnelere işaretçiler olarak adlandırılırlar. .NET'te opaktırlar. Ne olduklarını bilmiyoruz. Bizim bakış açımıza göre onlar nesnenin "tutamaçları"). Bu süreler, Değer Türlerine benzer (kopya ile aktarılır). Dolayısıyla bir nesne, nesneden (bir başvuru türü) ve ona sıfır veya daha fazla başvurudan (değer türlerine benzer) oluşur. Sıfır referans olduğunda, GC muhtemelen bunu toplayacaktır.

Genel olarak (.NET'in "varsayılan" uygulamasında), Değer türü yığına (yerel alanlarsa) veya öbeğe (eğer bunlar bir sınıfın alanlarıysa, bir yineleyici işlevindeki değişkenlerse, eğer bir kapanış tarafından başvurulan değişkenlerse, bir zaman uyumsuz işlevde değişken iseler (daha yeni Async CTP kullanarak) ...). Başvurulan değer yalnızca yığına gidebilir. Referanslar, Değer türleriyle aynı kuralları kullanır.

Bir yineleyici işlevinde, zaman uyumsuz bir işlevde oldukları için veya bir kapanış tarafından başvurulduğu için öbek üzerine giden Değer Türü durumlarında, derlenen dosyayı izlerseniz, derleyicinin bu değişkenleri koymak için bir sınıf oluşturduğunu görürsünüz. ve işlevi çağırdığınızda sınıf oluşturulur.

Şimdi, uzun şeyleri nasıl yazacağımı bilmiyorum ve hayatımda yapacak daha iyi şeylerim var. "Kesin" "akademik" "doğru" bir sürüm istiyorsanız, BUNU okuyun:

http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx

15 dakika onu arıyorum! Msdn sürümlerinden daha iyidir çünkü yoğunlaştırılmış "kullanıma hazır" bir makale.


1
Ezoterik yönlerden çok yanlış. Bu var temelde söyleyebilirim yanlış - başvuru türü değerleri hala yanı değer geçirilir çünkü; sadece değer bir nesne değil, bir referanstır. Bkz. Pobox.com/~skeet/csharp/parameters.html . Oh, ve yerel değişkenler de, örneğin yakalandıklarında veya bir yineleme bloğunun parçası olduklarında, yığında yer alabilir.
Jon Skeet

Yineleyici blokları sınıflara dönüştürülür, bu nedenle "arkanızda" onlar "bir sınıfın alanlarıdır". Kapanışlar için aynı. Evet ... "işaretçi" (referans) ile "sivri uçlu" arasındaki farkı yazmayı unuttum
xanatos

@xanatos: Elbette, derlemeden sonra bir sınıfın alanları - ama yine de kaynak kodda yerel değişkenler. Referansların kendilerine "değer türleri" de demezdim - Sanırım nereden geldiğinizi biliyorum, ancak suları bu şekilde bulandırmanın iyi bir fikir olduğunu düşünmüyorum.
Jon Skeet

@jon Evet ... Bunlar üçüncü bir tür, çünkü işaretçiler .net'te "opaktır" ve ValueType'tan türetilmezler. Ancak referanslardan çok değer türlerine benzerler. Onları "ref" ve "out" yapabilirsiniz. Suları çamurlamak zorunda kaldım çünkü "biri" yineleyicilerin işleyişini nitelendirmek zorunda kaldı.
xanatos

Şimdi işaret ettiğim makaleye baktığımda, şunu buldum: "Üç tür değer vardır: (1) değer türü örnekleri, (2) başvuru türü örnekleri ve (3) referanslar. (C # kodundaki kod değiştirilemez doğrudan referans türlerinin örnekleri; bunu her zaman bir referans yoluyla yapar. Güvenli olmayan kodda, işaretçi türleri, değerlerinin depolama gereksinimlerini belirlemek amacıyla değer türleri gibi değerlendirilir. ) ".
xanatos

0

Başvuru türlerini düşünmenin en basit yolu, onları "nesne kimlikleri" olarak düşünmektir; bir nesne kimliği ile yapılabilecek tek şey bir tane oluşturmak, birini kopyalamak, birinin türünü sorgulamak veya değiştirmek veya eşitlik için ikisini karşılaştırmaktır. Bir nesne kimliğiyle başka bir şey yapma girişimi, bu kimlik tarafından atıfta bulunulan nesne ile belirtilen eylemi gerçekleştirmenin kısa yolu olarak kabul edilecektir.

Bir referans türü olan Araba türünde X ve Y olmak üzere iki değişkenim olduğunu varsayalım. Y, "nesne kimliği # 19531" tutar. "X = Y" dersem, bu X'in "nesne kimliği # 19531" tutmasına neden olur. Ne X ne de Y'nin araba tutmadığını unutmayın. Aksi takdirde "nesne kimliği # 19531" olarak bilinen araba başka bir yerde saklanır. Y'yi X'e kopyaladığımda, tek yaptığım kimlik numarasını kopyalamaktı. Şimdi X.Color = Colors.Blue dediğimi varsayalım. Böyle bir ifade, "nesne kimliği # 19531" bulmak ve maviye boyamak için bir talimat olarak kabul edilecektir. X ve Y artık sarı bir arabadan ziyade mavi bir arabaya atıfta bulunsa da, ifadenin gerçekte X veya Y'yi etkilemediğini unutmayın, çünkü her ikisi de hala kendisiyle aynı araba olan "nesne kimliği # 19531" her zaman olmuştur.


0

Değişken türleri ve Referans Değerinin uygulanması kolaydır ve alan modeline iyi uygulanır, geliştirme sürecini kolaylaştırır.

"Değer türü" miktarıyla ilgili herhangi bir efsaneyi ortadan kaldırmak için, bunun platformda nasıl ele alındığı hakkında yorum yapacağım. .

C # 'da Değişken Tür Değeri ve Başvurusu makalesini okuyun


Bu, maalesef = \, yalnızca İngilizce bir Soru-Cevap sitesidir. Yine de cevap vermeye çalıştığınız için teşekkürler. Lütfen yalnızca yardım amaçlı bağlantılar içeren tam yanıtlar oluşturun (ancak tam yanıt olarak değil). Lütfen nasıl cevap vereceğinize bir göz atın .
Jesse,

0

vBir değer türü ifade / değişken ve rbir referans türü ifade / değişken olduğunu varsayalım

    x = v  
    update(v)  //x will not change value. x stores the old value of v

    x = r 
    update(r)  //x now refers to the updated r. x only stored a link to r, 
               //and r can change but the link to it doesn't .

Dolayısıyla, değer türü bir değişken gerçek değeri (5 veya "h") depolar. Referans tipi değişken, yalnızca değerin olduğu mecazi bir kutuya bir bağlantı saklar.


0

C # 'da bulunan farklı veri türlerini açıklamadan önce, C #' ın kesin olarak yazılmış bir dil olduğunu belirtmek önemlidir. Bu, her değişken, sabit, giriş parametresi, dönüş türü ve genel olarak bir değer olarak değerlendirilen her ifadenin bir türü olduğu anlamına gelir.

Her tür, bellek ayırdığında ve geri aldığında tür güvenliğini garantilemek için ortak dil çalışma zamanı (CLR) tarafından kullanılacak üst veri olarak derleyici tarafından yürütülebilir dosyaya gömülecek bilgileri içerir.

Belirli bir türün ne kadar bellek ayırdığını bilmek istiyorsanız, sizeof operatörünü aşağıdaki gibi kullanabilirsiniz:

static void Main()
{
    var size = sizeof(int);
    Console.WriteLine($"int size:{size}");
    size = sizeof(bool);
    Console.WriteLine($"bool size:{size}");
    size = sizeof(double);
    Console.WriteLine($"double size:{size}");
    size = sizeof(char);
    Console.WriteLine($"char size:{size}");
}

Çıktı, her değişken tarafından ayrılan bayt sayısını gösterecektir.

int size:4
bool size:1
double size:8
char size:2

Her türle ilgili bilgiler şunlardır:

  • Gerekli depolama alanı.
  • Maksimum ve minimum değerler. Örneğin, Int32 türü 2147483648 ile 2147483647 arasındaki değerleri kabul eder.
  • Devraldığı temel tür.
  • Çalışma zamanında değişkenler için belleğin ayrılacağı konum.
  • İzin verilen işlem türleri.
  • Türün içerdiği üyeler (yöntemler, alanlar, olaylar vb.). Örneğin, int türünün tanımını kontrol edersek, aşağıdaki yapı ve üyeleri bulacağız:

    namespace System
    {
        [ComVisible(true)]
        public struct Int32 : IComparable, IFormattable, IConvertible, IComparable<Int32>, IEquatable<Int32>
        {      
            public const Int32 MaxValue = 2147483647;     
            public const Int32 MinValue = -2147483648;
            public static Int32 Parse(string s, NumberStyles style, IFormatProvider provider);    
            ... 
        }  
    }

Bellek yönetimi Bir işletim sisteminde birden fazla işlem çalışırken ve RAM miktarı hepsini tutmak için yeterli olmadığında, işletim sistemi sabit diskin parçalarını RAM ile eşler ve verileri sabit diskte depolamaya başlar. İşletim sistemi, isteği gerçekleştirmek için sanal adreslerin karşılık gelen fiziksel adresleriyle eşlendiği belirli tablolardan daha fazlasını kullanacaktır. Bu belleği yönetme özelliğine sanal bellek denir.

Her süreçte, mevcut sanal bellek aşağıdaki 6 bölümde düzenlenmiştir, ancak bu konunun alaka düzeyi için sadece yığın ve yığın üzerine odaklanacağız.

Yığın Yığın , boyuta bağlı olarak işletim sistemine bağlı bir LIFO (son giren, ilk çıkar) veri yapısıdır (varsayılan olarak, ARM, x86 ve x64 makineleri için Windows'un rezervi 1MB iken, Linux, işletim sistemine bağlı olarak 2MB ila 8MB sürüm).

Belleğin bu bölümü otomatik olarak CPU tarafından yönetilir. Bir işlev yeni bir değişken bildirdiğinde, derleyici yığın üzerindeki boyutu kadar yeni bir bellek bloğu ayırır ve işlev bittiğinde, değişken için bellek bloğu serbest bırakılır.

Yığın Bu bellek bölgesi, CPU tarafından otomatik olarak yönetilmez ve boyutu yığından daha büyüktür. Yeni anahtar sözcük çağrıldığında, derleyici isteğin boyutuna uyan ilk boş bellek bloğunu aramaya başlar. ve onu bulduğunda, yerleşik C işlevi malloc () kullanılarak ayrılmış olarak işaretlenir ve işaretçiyi o konuma döndürür. Ayrıca, yerleşik C işlevi free () kullanarak bir bellek bloğunu serbest bırakmak da mümkündür. Bu mekanizma bellek parçalanmasına neden olur ve doğru bellek bloğuna erişmek için işaretçiler kullanmak zorundadır, okuma / yazma işlemlerini gerçekleştirmek yığından daha yavaştır.

Özel ve Yerleşik türler C #, tam sayıları, boolean, metin karakterlerini vb. Temsil eden standart bir yerleşik tür kümesi sağlarken, kendi türlerinizi oluşturmak için struct, sınıf, arabirim ve enum gibi yapıları kullanabilirsiniz.

Struct yapısını kullanan özel bir tür örneği:

struct Point
{
    public int X;
    public int Y;
};

Değer ve başvuru türleri C # türünü aşağıdaki kategorilere ayırabiliriz:

  • Değer türleri
  • Referans türleri

Değer türleri Değer türleri System.ValueType sınıfından türetilir ve bu türdeki değişkenler, yığıntaki bellek ayırmaları içinde değerlerini içerir. İki değer türü kategorisi struct ve enum'dur.

Aşağıdaki örnek, boole türünün üyesini gösterir. Gördüğünüz gibi, System.ValueType sınıfına açık bir başvuru yoktur, bunun nedeni bu sınıfın struct tarafından miras alınmasıdır.

namespace System
{
    [ComVisible(true)]
    public struct Boolean : IComparable, IConvertible, IComparable<Boolean>, IEquatable<Boolean>
    {
        public static readonly string TrueString;
        public static readonly string FalseString;
        public static Boolean Parse(string value);
        ...
    }
}

Referans türleri Diğer yandan, referans türleri bir değişkende depolanan gerçek verileri içermez, ancak değerin depolandığı yığının bellek adresini içerir. Başvuru türlerinin kategorileri, sınıflar, temsilciler, diziler ve arabirimlerdir.

Çalışma zamanında, bir başvuru türü değişkeni bildirildiğinde, ona new anahtar sözcükleri kullanılarak oluşturulan bir nesne atanıncaya kadar null değerini içerir.

Aşağıdaki örnek, genel tür List'in üyelerini gösterir.

namespace System.Collections.Generic
{
    [DebuggerDisplay("Count = {Count}")]
    [DebuggerTypeProxy(typeof(Generic.Mscorlib_CollectionDebugView<>))]
    [DefaultMember("Item")]
    public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
    {
        ...
        public T this[int index] { get; set; }
        public int Count { get; }
        public int Capacity { get; set; }
        public void Add(T item);
        public void AddRange(IEnumerable<T> collection);
        ...
    }
}

Belirli bir nesnenin bellek adresini bulmak istemeniz durumunda, System.Runtime.InteropServices sınıfı, yönetilmeyen bellekten yönetilen nesnelere erişmek için bir yol sağlar. Aşağıdaki örnekte, bir dizeye bir tutamaç ayırmak için statik GCHandle.Alloc () yöntemini ve ardından adresini almak için AddrOfPinnedObject yöntemini kullanacağız.

string s1 = "Hello World";
GCHandle gch = GCHandle.Alloc(s1, GCHandleType.Pinned);
IntPtr pObj = gch.AddrOfPinnedObject();
Console.WriteLine($"Memory address:{pObj.ToString()}");

Çıktı olacak

Memory address:39723832

Referanslar Resmi belgeler: https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=vs-2019


-1

Standartta açıkça ifade edilen değer türleri ve referans türleri arasındaki farkların pek çok küçük detayı vardır ve bunlardan bazılarının anlaşılması özellikle yeni başlayanlar için kolay değildir.

ECMA standardı 33, Ortak Dil Altyapısı (CLI) bölümüne bakın . CLI ayrıca ISO tarafından standartlaştırılmıştır. Bir referans sağlardım, ancak ECMA için bir PDF indirmemiz gerekir ve bu bağlantı sürüm numarasına bağlıdır. ISO standartları maliyetlidir.

Bir fark, değer türlerinin kutu içine alınabilmesidir, ancak başvuru türleri genellikle olamaz. İstisnalar var ama oldukça teknikler.

Değer türlerinin parametresiz örnek oluşturucuları veya sonlandırıcıları olamaz ve kendilerine başvuruda bulunamazlar. Kendilerine referansla bir değer türü olup olmadığını Yani örneğin düğüm daha sonra bir üyesi düğüm bir olamaz Düğüm . Spesifikasyonlarda başka şartlar / sınırlamalar olduğunu düşünüyorum, ancak öyleyse tek bir yerde toplanmıyorlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.