Comment sont les chaînes de transmission .NET?
Lorsque je passe un string
à une fonction est un pointeur vers la chaîne du contenu transmis, ou est l'ensemble de la chaîne de caractères passée à la fonction sur la pile comme un struct
serait?
Vous devez vous connecter pour publier un commentaire.
Pour répondre à votre question, considérons le code suivant:
Il y a trois choses que vous devez savoir afin de prédire ce qui va se passer ici, et de comprendre pourquoi il le fait.
strMain
n'est pas passé par référence. C'est un type de référence, mais la référence est passé par valeur. C'est une délicate distinction, mais il est d'une importance cruciale. Tout le temps que vous passez un paramètre sans leref
mot-clé (sans compterout
paramètres), vous avez réussi quelque chose de valeur.Mais qu'est-ce que cela signifie?
De référence passant types par valeur: Vous êtes déjà faire
Il y a deux groupes de types de données en C#: types de référence et types de valeur. Il y a aussi deux façons de passer des paramètres en C#: par référence et en valeur. Ces sonner de la même façon et sont facilement confondus. Ils ne sont PAS la même chose!
Si vous passez un paramètre de n'IMPORTE quel type, et que vous n'utilisez pas le
ref
mot-clé, vous avez passé par valeur. Si vous avez passé par valeur, ce que vous avez vraiment passé était une copie. Mais si le paramètre est un type de référence, alors la chose que vous avez copié est la référence, pas ce qu'il pointait.Voici la première ligne de notre
Main
méthode:Il y a deux choses que nous avons créé sur cette ligne: une chaîne de caractères avec la valeur
main
stockées en mémoire quelque part, et une variable de référence appeléstrMain
pointant vers elle.Maintenant nous transmettre cette référence à
DoSomething
. Nous avons passé par valeur, ce qui signifie que nous avons fait une copie. Mais c'est un type de référence, ce qui signifie que nous avons copié la référence, et non la chaîne elle-même. Maintenant, nous avons deux références que chaque point de la même valeur dans la mémoire.À l'intérieur de l'appelant
Voici le haut de la
DoSomething
méthode:Pas
ref
mot-clé, comme d'habitude. DoncstrLocal
n'est passtrMain
, mais ils pointent vers le même endroit. Si l'on peut "changer"strLocal
, comme ça......nous n'avons pas changé la valeur stockée en soi. Nous avons re-signalé la référence. Nous avons pris la référence
strLocal
et il vise à une nouvelle marque de la chaîne. Ce qui se passe àstrMain
quand nous faisons cela? Rien. Il pointe toujours à la vieille chaîne!Immutabilité est important
Nous allons changer le scénario pour une seconde. Imaginez que nous ne travaillez pas avec des chaînes, mais certains mutable type de référence, comme une classe que vous avez créé.
Si vous suivre la référence
objLocal
à l'objet de points, vous pouvez modifier ses propriétés:Il n'y a toujours qu'un seul
MutableThing
dans la mémoire, et à la fois la copie de référence et la référence d'origine pointent toujours vers elle. Les propriétés de l'MutableThing
lui-même ont changé:Ah, mais...
...les chaînes sont immuables! Il n'y a pas
ChangeMe
propriété à définir. Vous ne pouvez pas fairestrLocal[3] = 'H';
comme vous pouvez avec un style C char tableau; vous avez à construire une toute nouvelle chaîne à la place. La seule façon de changerstrLocal
est-à-point de la référence à une autre chaîne, et qui ne signifie rien vous faire pourstrLocal
peut affecterstrMain
. La valeur est immuable, et la référence est une copie.Ainsi, même si les chaînes sont des types référence, en passant par la valeur, c'est tout ce qui se passe dans le destinataire de l'appel ne sera pas affecter la chaîne en l'appelant. Mais, depuis qu'ils sont types de référence, vous n'avez pas à copier l'ensemble de la chaîne de caractères en mémoire lorsque vous voulez passer autour.
D'autres ressources:
ref
mot-clé. Pour prouver que le passage par référence fait une différence, voir cette démo: rextester.com/WKBG5978ref
mot-clé a une utilité, j'essayais juste d'expliquer pourquoi l'une à penser le passage d'un type de référence par valeur en C# me semble que le "traditionnel" (c-C) notion de passage par référence (et le passage d'un type de référence par référence en C# semble de plus en plus comme de passer une référence à une référence de la valeur).Foo(string bar)
pourrait être considéré commeFoo(char* bar)
alors queFoo(ref string bar)
seraitFoo(char** bar)
(ouFoo(char*& bar)
ouFoo(string& bar)
en C++). Bien sûr, ce n'est pas la façon dont vous devriez penser à elle tous les jours, mais en fait elle m'a aidé à enfin comprendre ce qui se passe sous le capot.Chaînes de caractères en C# sont immuables objets de référence. Cela signifie que les références à eux sont passés (en valeur), et une fois qu'une chaîne est créé, vous ne pouvez pas le modifier. Les méthodes qui produisent des versions modifiées de la chaîne (chaînes, garni de versions, etc.) créer modifié copies de la chaîne d'origine.
Les chaînes de caractères sont des cas particuliers. Chaque instance est immuable. Lorsque vous modifiez la valeur d'une chaîne de caractères que vous allouez une nouvelle chaîne de caractères en mémoire.
Donc, seule la référence est transmise à votre fonction, mais, quand la chaîne est modifiée, elle devient une nouvelle instance et ne modifie en rien de l'ancienne instance.
StringBuilder
est une mutable classe string qui permet la modification rapide de la chaîne construite sans l'attribution de nouvelles chaînes dans la mémoire de chaque modification.Uri
(la classe) etGuid
(struct) sont également des cas spéciaux. Je ne vois pas commentSystem.String
agit comme un "type de valeur", pas plus que les autres immuable types... de classe ou structure origines.Uri
&Guid
- vous pouvez simplement assigner une chaîne littérale valeur à une variable de chaîne. La chaîne semble être mutable, comme unint
être réaffectés, mais c'est la création d'un objet implicitement - pas denew
mot-clé.==
comparaison de la valeur) peut être facilement transposé dans les types définis par l'utilisateur. Je ne voudrais pas les décrire comme de se comporter comme des types de valeur.