Pregunta

Aquí es lo que entiendo hasta ahora:

PASO POR VALOR

Se pasa por valor significa que una copia de un argumento se pasa.Cambios de la copia no cambiar el original.

PASO POR REFERENCIA

Paso por referencia, una referencia a la original se pasa.los cambios en la referencia que afectan a la original.

Palabra Clave REF

REF le dice al compilador que el objeto se inicializa antes de entrar a la función.REF significa que el valor ya está establecido, el método puede, por tanto, leer y modificar.REF es de dos maneras, tanto dentro como fuera.

Palabra Clave OUT

FUERA le dice al compilador que el objeto se intialized dentro de la función.Significa que el valor no está establecido, y por lo tanto se debe establecer antes de llamar a devolver.CABO es sólo una manera, la que está fuera.

Pregunta

Así, en qué escenarios que combinan el uso de las palabras clave ref y out, con el paso por referencia o se pasa por valor?Ejemplos ayudaría enormemente.

Ayuda muy apreciada.

¿Fue útil?

Solución

Se podría no combinar ref y out el 1 de parámetro. Ambos significan 'pasan por referencia'.

Por supuesto, puede combinar los parámetros ref y parámetros out en un método.

La diferencia entre ref y out radica principalmente en intención . señales al árbitro de transporte de datos de 2 vías, hacia fuera significa 1-manera.

Pero además de la intención, el compilador de C # rastrea definitiva-misiones y que marca la diferencia más notable. También evita el mal uso (lectura) de un parámetro de salida.

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
}

Otros consejos

  

Ayuda muy apreciada

Su comprensión será mejorada por un uso correcto y cuidadoso del lenguaje.

  

El paso por valor, se pasa una copia de un argumento.

Sí, esto es exactamente precisa.

  

Los cambios en esa copia no cambian el original.

No exactamente. Primero distinguir cuidadosamente entre valores y las variables . Considere lo siguiente:

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
}

Las variables aquí son x, y bla foo. x es un campo, bla, es un local, foo es un parámetro formal.

Los valores aquí son null, 0, 123, y una referencia a una instancia de Foo. Esta referencia es un valor. Es crucial comprender este hecho.

Una copia del valor de bla se pasa copiando el valor de la variable en bla variable foo. El valor de bla es una referencia a la instancia de Foo.

M puede cambiar el valor de la variable x porque M tiene una copia del valor de bla, que es una referencia a un Foo. Cuando M cambia el contenido de foo a nulo, eso no cambia bla; foo contiene una copia del valor de bla.

  

paso por referencia significa que se pasa una referencia a la original.

Cambiar la redacción cuidadosamente. ¿Qué es "el original"?

Esto sería mejor dicho como "que pasa por referencia significa que una referencia al argumento, que debe ser una variable, se pasa". Una forma más fácil pensar en ello es que "el paso por referencia hace que el parámetro de un alias para la variable pasada como argumento".

  

cambios en la referencia afectan a la original.

Dado que el parámetro y el argumento son alias para cada otro, no es que los cambios en la referencia afectan el original; La referencia es el original. Ellos son a la vez la misma variable .

  

REF le dice al compilador que el objeto se inicializa antes de entrar en la función.

"El objeto" no tiene sentido. ¿Quieres decir que "la variable".

"ref" no "decirle al compilador que se inicializa la variable". Más bien, "ref" le dice al compilador "que, compilador, debe verificar que la variable se inicializa". Esto es bastante diferente!

  

significa REF ya está establecido el valor,

No, ref requiere que el variables ya se ha ajustado. No hay tal cosa como "el establecimiento de un valor".

  

Por lo tanto, el método puede leerlo y modificarlo.

Cuando en "eso" que significa "la variable".

  

REF es de dos maneras, tanto dentro como fuera.

correcta.

  

OUT indica al compilador que el objeto será inicializado dentro de la función.

Deje de usar "objeto" para significar "la variable". Usted va a entender las cosas mucho más claramente si deja de confundir las cosas completamente diferentes. Las variables no son objetos. Las variables son ubicaciones de almacenamiento algunos de los cuales podrían contener Los valores , y algunos de esos valores podrían ser referencias a objetos .

Por lo tanto, salir le dice al compilador que la variable se inicializa dentro del método, sí, pero eso no es del todo correcto. Están olvidando sobre los casos en que el método va a lanzar una excepción, o el método entra en un bucle infinito - Esas son también escenarios legales.

  

significa OUT no está ya establecer el valor,

Una vez más, por "el valor", que quiere decir "la variable". Pero esto no es exacto. Es perfectamente legal para pasar una variable inicializada como un parámetro "out". No tiene sentido, pero legal.

  

y por lo tanto se debe establecer antes de llamar retorno.

"retorno" no se llama; métodos se llaman. Pero sí, el método debe asignar un valor a la variable antes de returning normalmente.

  

OUT es sólo una forma, que está fuera.

derecho.

  

Así que en lo que serían los escenarios que combinan el uso de las palabras clave árbitro y fuera

No hay tales escenarios.

Usted entiende la dinámica de pasar de cualquier manera. Algunos escenarios de parámetros pueden ser:

  • ref int num para una en el parámetro de entrada / salida. La función puede modificar el valor en él.
  • out int num como ref excepto función debe asignar un valor a la misma antes de regresar.

En los parámetros de salida generales son buenos para cuando una función debe devolver varios valores, porque una función sólo tiene un valor de retorno (aunque puede ser compuesto).

A veces los proveedores de acceso a los datos, al igual que algunos métodos de ADO.NET, utilizan parámetros de salida para entregar información de nuevo. Algunos métodos de acceso a datos de bases de datos imitan los procedimientos almacenados que tienen parámetros de entrada / salida.

Editar: Una estipulación para los tipos de referencia es la ref StringBuilder word parámetros o StringBuilder word (por valor) se comportan de la misma - la cadena exterior se ve afectada, aunque la implementatoin subyacente puede ser ligeramente diferente porque en ese momento el foco es la referencia y no el valor en el montón.

Editar He corregido esta respuesta para reflejar que la palabra clave 'hacia fuera' en C # no hace lo que se podría esperar que (por ejemplo, un cierto parámetro OUT en el sentido de la informática del término ). He dicho al principio que 'hacia fuera' era paso por valor fuera, pero estaba equivocado.

No se puede utilizar 'out' y 'ref' juntos. Hay tres convenciones de llamada en C # (.NET Framework):

  • No hay palabra clave = paso por valor (EN)
  • 'hacia fuera' palabra clave = Pass por referencia (REF) sin necesidad de asignación definida antes de la llamada
  • 'ref' Keyword = Pass por referencia (REF) con un requisito de asignación definida antes de la llamada

C # no tiene verdadera OUT o la capacidad parámetro IN-OUT.

Para ver que los parámetros 'out' en C # no son verdaderos parámetros OUT, puede utilizar el siguiente código:

  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 salida es:

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

Como se puede ver, tanto fuera '' y 'ref' pasan realmente por el momento. La única diferencia está en cómo el compilador los trata con fines de asignación definidas.

El uso de la palabra clave OUT es útil si tiene un método que tiene que devolver más de un valor. Por ejemplo, mirar a métodos como int.TryParse().

El uso de REF es más por lo explícito de objetos. Teniendo en cuenta que cualquiera que no sea primitiva pasó a un método es inherentemente pasado por referencia no es mucha necesidad de ella en código administrado normal. Al declarar la palabra clave REF estás indicando que el parámetro es probable que se modifica en el cuerpo del método y por lo tanto el código de llamada debe ser consciente de que (por lo tanto eso que hay que añadir explícitamente el ref en el código de llamada también.

Si usted entiende c ++ tal vez esto le ayudará a:

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)

Se pasa por algo ref desea ser leído y escrito por otra función, por lo que debe pasar la variable inicializada con el fin de ser leído correctamente.

EDIT: ejemplo:

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

Se pasa como algo que desea ser escrita por otra función, pero no es necesario para inicializar, ya que no será leído por la función, sólo por escrito.

EDIT: ejemplo:

void mymethod2(out string a) {
  a="hello";
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top