Nasıl dizeleri geçti .NET?
Zaman geçer string
bir işlevi, bir işaretçi dize içeriğini geçti, yoksa tüm dize geçirilen işlev yığını gibi bir struct
olurdu?
CEVAP
Sorunuzu yanıtlamak için, şu kodu göz önünde bulundurun:
void Main()
{
string strMain = "main";
DoSomething(strMain);
Console.Write(strMain); // What gets printed?
}
void DoSomething(string strLocal)
{
strLocal = "local";
}
Burada ne olacağını tahmin etmek için bilmek ve anlamak gereken üç şey var.
- Dizeler C başvuru türleri#. Ama bu resmin sadece bir parçası.
- Ayrıca sabit, dize değiştiriyorsun gibi görünen bir şey herhangi bir zaman, değil mi. Tamamen yeni bir dize oluşturulan alır, başvuru işaret ve eskisini çöpe atmak olur.
- Dizeleri olmasına rağmen başvuru türleri,
strMain
başvuru tarafından geçirilen değil. Birbaşvuru yazınama referans ediliyordeğeri tarafından geçirilen. Bu zor bir fark var, ama önemli değil.ref
anahtar olmadan bir parametre geçirmek her zaman (out
parametreleri hariç), değer bir şey geçti.
Ama bu ne anlama geliyor?
Değeriyle geçirmeden başvuru türleri: zaten yapıyorsun
C veri türleri iki gruba ayrılır#:başvuru türlerivedeğer türleri. Ayrıca C parametreleri için iki yol vardır#:başvuruylavedeğer. Aynı bu ses ve kolayca karışır. Aynı şey değiller!
HERHANGİ bir parametre geçirmek ve ref
anahtar kelime kullanmak istemiyorsanız, o zaman değeri ile geçtin. Eğer değer geçti, gerçekten geçti ne bir kopyası oldu. Amaeğer parametre bir başvuru türü ise, o zaman kopyalanan şey referans olduişaret değildi her neyse.
İşte Main
bizim yönteminin ilk satırı:
string strMain = "main";
Aslında bu hat üzerinde yarattığımız iki şey vardır: main
bellekte bir yerlerde saklı, ve bir referans değişken strMain
işaret adında bir dize değeri ile.
DoSomething(strMain);
Şimdi DoSomething
başvuru geçiyoruz. Değeri ile onu geçtik, bir kopyasını yaptık. Ama bir başvuru türü, başvuru, dize kendisi kopyaladık değil yani. Şimdi her bellek aynı değer için iki başvuru var.
Aranan içeride
Burada DoSomething
yöntemi üst:
void DoSomething(string strLocal)
ref
hiçbir kelime, her zamanki gibi. strLocal
strMain
değil, ama onlar aynı yere işaret de değil. Biz "değişim" strLocal
bu gibi
strLocal = "local";
...vermedikdeğiştisaklı değer aslında. Re-sivri başvuru yaptık. Başvuru strLocal
adlı aldık ve yepyeni bir dize doğrulttu. Bunu yaptığımız zaman strMain
ne olacak? Nothing. It's still pointing at the old string!
string strMain = "main"; //Store a string, create a reference to it
DoSomething(strMain); //Reference gets copied, copy gets re-pointed
Console.Write(strMain); //The original string is still "main"
Değişmezliğini tanıdı önemlidir
Hadi bir an için senaryoyu değiştirin. Dizelerle çalışmaya değiliz, ama bazı değişken referans türü, oluşturduğunuz bir sınıf gibi düşün.
class MutableThing
{
public int ChangeMe { get; set; }
}
Eğerizleyinbaşvuru objLocal
nesneye işaret, onun özelliklerini değiştirebilirsiniz:
void DoSomething(MutableThing objLocal)
{
objLocal.ChangeMe = 0;
}
Hala bellekte 35 ** sadece bir tane var, ve kopyalanan referans ve orijinal referans hem de bunu gösteriyor. 44**:
void Main()
{
var objMain = new MutableThing();
objMain.ChangeMe = 5;
Console.Write(objMain.ChangeMe); //it's 5 on objMain
DoSomething(objMain); //now it's 0 on objLocal
Console.Write(objMain.ChangeMe); //it's also 0 on objMain
}
Ah, ama...
...dizeleri değişmez! Ayarlamak için ChangeMe
özelliği yok. C-tarzı bir char dizisi ile senin gibi strLocal[3] = 'H';
yapamazsın; yepyeni bir dize yerine inşa etmek zorunda. strLocal
değiştirmenin tek yolu başka bir dize de referans noktası, 41* *sen hiçbir şey yapma strMain
etkileyebilir anlamına gelir. Değeri sabittir ve referans bir kopyasıdır.
Yani dizeleri başvuru türleri olmasına rağmen, değeri geçirmeden aranan arayan dize etkilemez giden ne olursa olsun anlamına gelir. Ama o zamandan beri onlarbaşvuru türleri, geçmek istediğinizde hafıza, tüm dize kopyalamak zorunda değilsiniz.
Ek kaynaklar:
- Burada bir başvuru türü başvuru-geçirilen bir parametre olarak aynı değil neden the difference between reference types and value types in C# ve üzerine okuduğum en iyi yazı.
- Her zamanki gibi, Eric Lippert de several excellent blog posts on the subject vardır.
- 47* *da var.
Nasıl C rasgele alfanümerik dizeleri o...
Nasıl verimli bir şekilde Gidip dizele...
Nasıl Bash komut dizeleri...
Nasıl dal dizeleri bitiştirmek için...
Nasıl SQL Server dizeleri bitiştirmek ...