12
votes

Référence à la référence en C #?

Comme nous le savons tous, les objets C # cles sont traités comme des références, alors que se passe-t-il lorsque vous transmettez un objet de référence comme référence à une méthode? Dire que nous avons: xxx pré>

et ensuite: p> xxx pré>

est le compilateur que le compilateur découvre que a code> est déjà un Type de référence et conservez-le ainsi, ou il crée une nouvelle référence à cet objet? P>

Et si nous avons quelque chose comme ceci: p>

public void F(ref A a)
{
    F(ref a);
}


1 commentaires

Voir également par exemple Pourquoi utiliser mot-clé referf lorsque vous passez un objet? et les threads dans la section "liée" de la colonne à la Droite, à cette page.


6 Réponses :


1
votes

Simplement indiqué, passez une variable sous forme de paramètre Réf, c'est comme créer un alias pour la variable d'origine.

Les types de référence et les paramètres de référence sont des entités distinctes. Dans C # Variables, on passe toujours de la valeur. Cette valeur peut être une référence à un autre objet ou une valeur stockée.

En d'autres termes, les types de référence sont "passés par référence" car lorsque vous passez une instance d'objet à une méthode, la méthode obtient une référence à l'instance d'objet.
Dans le cas de paramètres de référence, la référence est à la variable (donc pourquoi il est logique de penser à cela un alias). Ceci est une forme différente de "passage par référence".

aller par votre exemple: xxx

ici c'est comme nous avons un seul objet (l'original paramètre A ) qui est référencé des temps infinis. (Notez que ce n'est pas ce que réellement arrive). Ce diagramme est destiné à fournir une représentation idiomatique de ce qui se passe sous les couvercles lorsqu'il s'agit de paramètres de référence.

Entrez la description de l'image ici

Voir la section 1.6.6.1 de La spécification 4.0 C # pour plus d'informations.


6 commentaires

Nope, A n'est pas un objet, c'est une référence à une variable contenant une référence à un objet.


@Benvoigt - Je veux dire qu'il peut être traité comme un seul objet, pas qu'il s'agisse d'un seul objet. Notez ce que j'ai dit à propos de "Alias". S'ils veulent tous les détails Nitty Gritty, ils peuvent voir la partie de la spécification que j'ai référencée.


En outre, cela n'a aucun sens de dire que "les variables sont toujours passées par la valeur". "Pass par valeur" implique le passage du paramètre, c'est-à-dire un argument, pas une variable.


@Benvoigt - respectueusement, je suis en désaccord. Eric Lippert a dit cela plusieurs fois (et je crois que Jon Skeet a dit la même chose dans une réponse par courrier électronique qu'il m'a envoyée une fois). De plus, pour moi, cela a beaucoup de sens lorsque vous envisagez "Paramètre de valeur" tel que défini dans la même section de la spécification.


Les variables sont des valeurs. Ils ne sont pas "passagers par valeur". "Pass par X" n'a de sens que lorsque vous parlez d'un paramètre, qui est passé.


@Benvoigt - Vous parlez de sémantique. Je parle d'intuition. Si l'OP veut la sémantique, il peut voir la spécification. Je propose un exemple intuitif qui vaut mieux pour quelqu'un qui essaie de saisir un concept.



2
votes

Les deux concepts ne sont pas les mêmes. Un paramètre de méthode peut être modifié par référence, qu'il s'agisse d'un type de valeur ou d'un type de référence.

Passer un type par référence permet la méthode appelée pour modifier l'objet référé par le paramètre ou pour modifier l'emplacement de stockage du paramètre. . P>

static void Main()
{
    Foo item = new Foo("aaa");
    GetByReference(ref item);
    Console.WriteLine(item.Name)
}
static void ChangeByReference(ref Foo itemRef)
{
    itemRef = new Foo("bbb");
}


0 commentaires

2
votes

Lorsque vous passez un objet comme paramètre d'une méthode, vous passez un nouveau pointeur qui fait référence à l'objet d'origine. Si vous passez un objet comme paramètre Réf, vous passez le même pointeur qui utilise la méthode de l'appelant. Un exemple, xxx

la sortie est 1 à 12 car le pointeur de l'objet B ne change pas mais l'objet d'origine change.


0 commentaires

28
votes

Ceci est mieux illustré avec un exemple: xxx

Que se passe-t-il?

q1 et c1 se réfèrent au même objet mais sont différentes variables. Mutating C1.P Mutates Q1.P car les deux variables font référence au même objet, Q1 est maintenant 11.

Q2 et C2 Reportez-vous au même objet, mais sont différentes variables. La mutation C2 ne mute pas q2 car c2 et q2 sont différentes variables; Changer on ne change pas l'autre. Q2 reste 2 et le nouvel objet est perdu.

Q3 et C3 sont deux noms pour la même variable et font donc référence au même objet. Lorsque vous modifiez C3.p, modifie automatiquement Q3.P, car ils sont deux noms pour la même chose.

Q4 et C4 sont deux noms pour la même variable, et par conséquent, la mutation du Q4 mutate également C4.

Cela a un sens?

Il est regrettable que le mot-clé de "faire un alias à cette variable" est "REF". Cela aurait été plus clair que c'était "alias".

Pour répondre à votre deuxième question: Non, cela ne fait pas une chaîne de références. Faisons un exemple plus clair: xxx

Ceci indique que C1 et Q1 sont des noms différents pour la même variable, et Q1 et Q2 sont des noms différents pour la même variable, et donc C1, Q1 et Q2 sont tous des alias les uns des autres. Il n'y a jamais de "référence à une référence à la variable" en C # comme il existe en C ++.


3 commentaires

Votre première méthode pourrait également être appelée comme m (q1, q2, ref qseame, ref qSame); et ensuite nous voyons qu'il est significatif que la ligne c3.p = 13; est avant la ligne c4 = nouveau c () {p = 14}; à l'intérieur de cette méthode.


Merci beaucoup, excellente réponse !!! Je n'aurais jamais pensé à ref comme alias , c'est vrai ce que vous dites sur le problème de nommage, le concept pourrait être mal compris. Merci beaucoup à nouveau.


@ E.Campver: La chose est, dans le système de type CLR, il existe des types de référence et il existe des types de "référence aux variables", et ils sont logiquement différents. Un paramètre REF provient de la perspective du système de type CLR A "Référence à la variable", mais à partir du point de vue du système de type C #, cela ressemble plus à un alias.



3
votes

ref crée simplement une référence à la valeur d'origine. Avec référence types de "valeur" est l'emplacement de la mémoire de la variable. Lorsque vous utilisez ref la méthode peut maintenant modifier la référence de la variable d'origine. Si vous faites la même chose avec un argument qui est déjà ref la 2e méthode a simplement la même référence que la première méthode a fait.


0 commentaires

4
votes

Dans un appel comme xxx

la variable A est "utilisé directement" par le corps de la méthode f . Il n'y a qu'un seul emplacement de stockage. Si la méthode f attribue à son paramètre, cette affectation sera visible à tous ceux qui peuvent voir a , immédiatement. Et inversement, si quelqu'un (extérieur f ) attribue à a pendant la méthode f exécute, puis le paramètre de f changera au nouvel objet "tout d'un coup".

d'autre part, dans un appel comme xxx

la variable Un est d'abord copié à une nouvelle variable, puis la nouvelle variable est utilisée à l'intérieur f . Maintenant, si le type de paramètre de f est un type type (comme un struct ou Enum ), copier est fait par valeur . De sorte que toutes les données sont copiées. Mais si le type de paramètre est un Type de référence ( class (type de tableau), interface , délégué ), la copie de a implique une copie de la référence uniquement.

à Vérifiez votre compréhension du paramètre de paramètre de valeur avec un paramètre de type de type , déterminez quelles sont ces méthodes: xxx

Voici un exemple éventuellement intéressant avec < Code> ref : xxx

comme exemple d'utilisation de g ci-dessus, considérez le code var x = " initiale"; G (réf x, ref x); auquel cas A va changer avec B à l'intérieur de la méthode g .


0 commentaires