Utilisation de mots clés REF & OUT avec passage par référence et passage par valeur en C #

StackOverflow https://stackoverflow.com/questions/1683394

  •  18-09-2019
  •  | 
  •  

Question

Voici ce que je comprends à ce jour:

PAR VALEUR PASS

Passe en valeur signifie une copie d'un argument est passé. Les modifications apportées à cette copie ne changent pas l'original.

REFERENCE DE PASSE

passage par référence, une référence à l'origine est transmis. des modifications à la référence affectent l'original.

REF Keyword

REF indique au compilateur que l'objet est initialisé avant d'entrer dans la fonction. REF signifie que la valeur est déjà défini, le procédé peut donc lire et modifier. REF est de deux façons, à la fois dedans et dehors.

OUT Mot

OUT indique au compilateur que l'objet sera intialized dans la fonction. OUT signifie que la valeur n'est pas déjà, et doit donc être avant d'appeler le retour. OUT est une seule façon, ce qui est en dehors.

Question

Alors dans quels scénarios auriez-vous combiner l'utilisation de l'arbitre et des mots-clés sur, en passant par référence ou en passant par la valeur? Les exemples pourraient aider énormément.

Aide grandement apprécié.

Était-ce utile?

La solution

Vous jamais combiner ref et out sur 1 paramètre. Ils signifient tous deux «passer par référence.

Vous pouvez bien sûr combiner les paramètres ref et paramètres en une seule méthode.

La différence entre ref et out réside principalement dans l'intention . signaux ref transport de données 2 voies, des moyens à 1 voie.

Mais en plus l'intention, le compilateur C # pistes-tâche définie et qui fait la différence la plus notable. Il empêche également l'utilisation abusive (lecture) d'un paramètre sur.

void SetOne(out int x) 
{
  int y = x + 1; // error, 'x' not definitely assigned.
  x = 1;         // mandatory to assign something
}

void AddTwo(ref int x)
{
    x = x + 2;  // OK, x  is known to be assigned
}

void Main()
{
    int foo, bar;

    SetOne(out foo); // OK, foo does not have to be assigned
    AddTwo(ref foo); // OK, foo assigned by SetOne
    AddTwo(ref bar); // error, bar is unassigned
}

Autres conseils

  

Aide très appréciée

Votre compréhension sera améliorée par une utilisation correcte et minutieuse de la langue.

  

Passe en valeur signifie une copie d'un argument est passé.

Oui, cela est tout à fait exact.

  

Les modifications apportées à cette copie ne changent pas l'original.

Pas exactement. Commencez par distinguer soigneusement entre valeurs et Variables . Considérez:

class Foo { public int x; }
...
void N() 
{
  Foo blah = new Foo();
  blah.x = 0;
  M(blah);
}
...
void M(Foo foo)
{
  foo.x = 123; // changes blah.x
  foo = null; // does not change blah
}

Les variables sont ici x, bla et foo. x est un champ, bla est un local, foo est un paramètre formel.

Les valeurs ici sont nulles, 0, 123, et une référence à une instance de Foo. Cette référence est une valeur. Il est crucial de comprendre ce fait.

Une copie de la valeur de bla est passée en copiant la valeur de la variable bla dans la variable foo. La valeur de bla est une référence à l'instance de Foo.

M peut modifier la valeur de la variable x parce que M a une copie de la valeur de bla, qui est une référence à un Foo. Lorsque M change le contenu de foo null, cela ne change rien bla; foo contient une copie de la valeur de bla.

  

passage par référence, une référence à l'origine est transmis.

Choisissez votre libellé soigneusement. Qu'est-ce que "l'original"?

Ce serait mieux indiqué que « le passage par référence signifie qu'une référence à l'argument, qui doit être une variable, est passé ». Un moyen plus facile de penser que « le passage par référence fait le paramètre un alias pour la variable passée comme argument ».

  

modifications à la référence affectent l'original.

Depuis le paramètre et l'argument sont des alias pour l'autre, ce n'est pas que les modifications de la référence affectent l'original; la référence est l'original. Ils sont tous deux la même variable .

  

REF indique au compilateur que l'objet est initialisé avant d'entrer dans la fonction.

« L'objet » n'a pas de sens. Vous voulez dire "la variable".

« ref » ne pas « dire au compilateur que la variable est initialisé ». Au contraire, « ref » indique au compilateur « vous, compilateur, devez vérifier que la variable est initialisée ». C'est plutôt différent!

  

REF signifie que la valeur est déjà définie,

Non, ref exige que la variable est déjà définie. Il n'y a pas une telle chose comme « la mise en valeur ».

  

le procédé peut donc lire et modifier.

Si par "ce" tu veux dire "la variable".

  

REF est deux façons, à la fois dedans et dehors.

Correct.

  

OUT indique au compilateur que l'objet sera intialized dans la fonction.

Arrêtez d'utiliser « l'objet » pour signifier « la variable ». Vous comprendrez les choses beaucoup plus clairement si vous arrêtez la confusion des choses complètement différentes. Les variables ne sont pas des objets. Les variables sont emplacements de stockage dont certains pourraient contenir des valeurs , et certaines de ces valeurs peuvent être références à des objets .

Alors, dit le compilateur que la variable sera initialisé dans la méthode, oui, mais ce n'est pas tout à fait raison. Tu oublies sur les cas où la méthode lèveront une exception, ou la méthode entrerez dans une boucle infinie - ce sont également des scénarios juridiques.

  

OUT signifie que la valeur n'est pas déjà,

Encore une fois, par « la valeur », vous voulez dire « la variable ». Mais ce n'est pas exact. Il est parfaitement légal de passer une variable initialisée comme paramètre « out ». Pointless, mais juridique.

  

et doit donc être avant d'appeler le retour.

« Retour » n'est pas appelé

; méthodes sont appelées. Mais oui, la méthode doit attribuer une valeur à la variable avant Returning normalement.

  

OUT est une seule façon, ce qui est en dehors.

Droit

.

  

Alors dans quels scénarios voulez-vous combiner l'utilisation des mots-clés ref et sur

Il n'y a pas de tels scénarios.

Vous comprenez la dynamique de passage dans les deux cas. Certains scénarios de paramètres peuvent être:

  • ref int num pour un paramètre in / out. La fonction peut modifier la valeur en elle.
  • out int num comme ref sauf fonction doit attribuer une valeur à elle avant de revenir.

Dans les paramètres de sortie généraux sont bons pour quand une fonction doit retourner plusieurs valeurs, car une fonction a une seule valeur de retour (bien qu'il puisse être composé).

Parfois, les fournisseurs d'accès aux données, comme certaines méthodes de ADO.NET, utilisez les paramètres de sortie pour fournir des informations de retour. Certaines méthodes d'accès aux données stockées simulent des procédures de base de données qui ont dans / sur les paramètres.

Modifier Une stipulation pour les types de référence est les paramètres ref StringBuilder word ou StringBuilder word (en valeur) se comportent de la même - la chaîne est affectée, bien que la implementatoin sous-jacente peut différer légèrement à l'extérieur parce qu'à ce moment la mise au point est la référence et non la valeur sur le tas.

Modifier J'ai corrigé cette réponse pour indiquer que le mot-clé « out » en C # ne fait pas ce que vous pouvez vous attendre à (par exemple un paramètre vrai OUT dans le sens de la science informatique du terme ). Au départ, je dit que « out » est passe par la valeur OUT mais il a été prouvé mal.

Vous ne pouvez pas utiliser « out » et « ref » ensemble. Il y a trois conventions d'appel en C # (NET Framework):

  • Aucun mot-clé = passer par valeur (IN)
  • 'out' Mot = Passe par référence (REF) sans obligation d'affectation définitive avant l'appel
  • 'ref' = Mot passe par référence (REF) avec une exigence d'affectation définitive avant l'appel

C # n'a pas vrai OUT ou paramètre IN-OUT capacité.

Pour voir que les paramètres « out » en C # ne sont pas vraies OUT paramètres, vous pouvez utiliser le code suivant:

  public class Test
  {
    Action _showValue;

    public void Run()
    {
      string local = "Initial";
      _showValue = () => { Console.WriteLine(local.ToString()); };

      Console.WriteLine("Passing by value");
      inMethod(local);

      Console.WriteLine("Passing by reference with 'out' keyword");
      outMethod(out local);

      Console.WriteLine("Passing by reference with 'ref' keyword");
      refMethod(ref local);

    }

    void inMethod(string arg)
    {
      _showValue();
      arg = "IN";
      _showValue();
    }

    void outMethod(out string arg)
    {
      _showValue();
      arg = "OUT";
      _showValue();
    }

    void refMethod(ref string arg)
    {
      _showValue();
      arg = "REF";
      _showValue();
    }
  }

La sortie est la suivante:

Passing by value
Initial
Initial
Passing by reference with 'out' keyword
Initial
OUT
Passing by reference with 'ref' keyword
OUT
REF

Comme vous pouvez le voir, les deux « out » et « ref » passent effectivement par REF. La seule différence est dans la façon dont le compilateur les traite à des fins d'affectation définitive.

En utilisant le mot-clé OUT est utile si vous avez une méthode que vous avez besoin de retourner plus d'une valeur. Par exemple, regardez des méthodes telles que int.TryParse().

Utilisation REF est plus pour explicitation des objets. En gardant à l'esprit que toute non-primitive passé dans une méthode est intrinsèquement passée par référence il n'y a pas beaucoup de besoin dans le code managé normal. En déclarant le mot-clé REF vous indiquant que le paramètre sera probablement modifié dans le corps de la méthode et donc le code d'appel doit être conscient (donc pourquoi vous devez ajouter explicitement le ref dans le code d'appel ainsi.

Si vous comprenez c ++ peut-être cela vous aidera à:

void Foo(Bar) {} // pass by value c# (if it's a value type ;))
void Foo(Bar) {} // c++

void Foo(Bar) {} // pass by reference c# (if it's a reference type ;))
void Foo(Bar&) {} // c++

void Foo(ref Bar) {} // c#
void Foo(Bar*) // c++

void Foo(out Bar) {} // c#
void Foo(Bar**) {} // c++ (the contents of *Bar needs to be filled up)

Vous passez par quelque chose ref vous voulez être lu et écrit par une autre fonction, vous devez passer à lire correctement la variable initialisée dans l'ordre.

EDIT: exemple:

void mymethod(ref int a) {
  a++;
}

Vous passez comme quelque chose que vous voulez être écrit par une autre fonction, mais vous n'avez pas besoin de l'initialiser car il ne sera pas lu par la fonction, uniquement par écrit.

EDIT: exemple:

void mymethod2(out string a) {
  a="hello";
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top