Quando passo a string
para uma função, é passado um ponteiro para o conteúdo da sequência ou toda a sequência é passada para a função na pilha como struct
seria?
fonte
Quando passo a string
para uma função, é passado um ponteiro para o conteúdo da sequência ou toda a sequência é passada para a função na pilha como struct
seria?
Uma referência é passada; no entanto, não é tecnicamente passado por referência. Esta é uma distinção sutil, mas muito importante. Considere o seguinte código:
void DoSomething(string strLocal)
{
strLocal = "local";
}
void Main()
{
string strMain = "main";
DoSomething(strMain);
Console.WriteLine(strMain); // What gets printed?
}
Há três coisas que você precisa saber para entender o que acontece aqui:
strMain
não são passadas por referência. É um tipo de referência, mas a própria referência é passada por valor . Sempre que você passa um parâmetro sem a ref
palavra - chave (sem contar os out
parâmetros), passa algo por valor.Então isso deve significar que você está ... passando uma referência por valor. Como é um tipo de referência, apenas a referência foi copiada na pilha. Mas o que isso significa?
Variáveis C # são tipos de referência ou tipos de valor . Os parâmetros C # são passados por referência ou passados por valor . A terminologia é um problema aqui; estes parecem a mesma coisa, mas não são.
Se você passa um parâmetro de QUALQUER tipo e não usa a ref
palavra - chave, passa-o por valor. Se você passou por valor, o que realmente passou foi uma cópia. Mas se o parâmetro era um tipo de referência, o que você copiava era a referência, não o que estava apontando.
Aqui está a primeira linha do Main
método:
string strMain = "main";
Criamos duas coisas nessa linha: uma string com o valor main
armazenado na memória em algum lugar e uma variável de referência chamada strMain
apontando para ela.
DoSomething(strMain);
Agora passamos essa referência para DoSomething
. Nós passamos por valor, o que significa que fizemos uma cópia. É um tipo de referência, o que significa que copiamos a referência, não a string em si. Agora, temos duas referências que apontam para o mesmo valor na memória.
Aqui está o topo do DoSomething
método:
void DoSomething(string strLocal)
Nenhuma ref
palavra-chave, portanto, strLocal
e strMain
são duas referências diferentes apontando para o mesmo valor. Se reatribuirmos strLocal
...
strLocal = "local";
... não alteramos o valor armazenado; pegamos a referência chamada strLocal
e apontamos para uma nova string. O que acontece strMain
quando fazemos isso? Nada. Ainda está apontando para a corda antiga.
string strMain = "main"; // Store a string, create a reference to it
DoSomething(strMain); // Reference gets copied, copy gets re-pointed
Console.WriteLine(strMain); // The original string is still "main"
Vamos mudar o cenário por um segundo. Imagine que não estamos trabalhando com strings, mas com algum tipo de referência mutável, como uma classe que você criou.
class MutableThing
{
public int ChangeMe { get; set; }
}
Se você seguir a referência objLocal
ao objeto para o qual ele aponta, poderá alterar suas propriedades:
void DoSomething(MutableThing objLocal)
{
objLocal.ChangeMe = 0;
}
Ainda existe apenas uma MutableThing
na memória, e a referência copiada e a referência original ainda apontam para ela. As propriedades do MutableThing
próprio foram alteradas :
void Main()
{
var objMain = new MutableThing();
objMain.ChangeMe = 5;
Console.WriteLine(objMain.ChangeMe); // it's 5 on objMain
DoSomething(objMain); // now it's 0 on objLocal
Console.WriteLine(objMain.ChangeMe); // it's also 0 on objMain
}
Ah, mas as cordas são imutáveis! Não há ChangeMe
propriedade para definir. Você não pode fazer strLocal[3] = 'H'
em C # como faria com uma char
matriz de estilo C ; você precisa construir uma sequência totalmente nova. A única maneira de mudar strLocal
é apontar a referência para outra string, e isso significa que nada que você faça strLocal
pode afetarstrMain
. O valor é imutável e a referência é uma cópia.
Para provar que há uma diferença, eis o que acontece quando você passa uma referência por referência:
void DoSomethingByReference(ref string strLocal)
{
strLocal = "local";
}
void Main()
{
string strMain = "main";
DoSomethingByReference(ref strMain);
Console.WriteLine(strMain); // Prints "local"
}
Desta vez, a string Main
realmente muda porque você passou a referência sem copiá-la na pilha.
Portanto, mesmo que as strings sejam tipos de referência, transmiti-las por valor significa que tudo o que acontece no receptor não afetará a string no chamador. Mas, como são tipos de referência, você não precisa copiar toda a cadeia de caracteres da memória quando quiser distribuí-la.
ref
palavra - chave. Para provar que passar por referência faz a diferença, veja esta demonstração: rextester.com/WKBG5978ref
palavra-chave tem utilidade. Estava apenas tentando explicar por que alguém poderia pensar em passar um tipo de referência por valor em C # parece a noção "tradicional" (isto é, C) de passar por referência (e passar um tipo de referência por referência em C # parece mais passar uma referência a uma referência por valor).Foo(string bar)
poderia ser pensado comoFoo(char* bar)
passo queFoo(ref string bar)
seriaFoo(char** bar)
(ouFoo(char*& bar)
ouFoo(string& bar)
em C ++). Claro, não é como você deve pensar nisso todos os dias, mas na verdade me ajudou a finalmente entender o que está acontecendo sob o capô.Strings em C # são objetos de referência imutáveis. Isso significa que as referências a eles são passadas (por valor) e, depois que uma string é criada, você não pode modificá-la. Os métodos que produzem versões modificadas da sequência (substrings, versões aparadas etc.) criam cópias modificadas da sequência original.
fonte
Strings são casos especiais. Cada instância é imutável. Quando você altera o valor de uma sequência, está alocando uma nova sequência na memória.
Portanto, apenas a referência é passada para sua função, mas quando a string é editada, ela se torna uma nova instância e não modifica a instância antiga.
fonte
Uri
(class) eGuid
(struct) também são casos especiais. Não vejo comoSystem.String
age como um "tipo de valor", mais do que outros tipos imutáveis ... de origem de classe ou estrutura.Uri
&Guid
- você pode apenas atribuir um valor literal de string a uma variável de string. A string parece ser mutável, como umint
ser reatribuído, mas está criando um objeto implicitamente - semnew
palavra-chave.