referencia pasar pasaje parametros parametro objetos funciones entre diferencia como clase argumentos c# reference keyword out ref

pasaje - pasar objetos como parametros en c#



¿Cuál es la diferencia entre las palabras clave ''ref'' y ''out''? (24)

afuera:

En C #, un método puede devolver solo un valor. Si desea devolver más de un valor, puede usar la palabra clave out. El modificador out regresa como retorno por referencia. La respuesta más simple es que la palabra clave "out" se usa para obtener el valor del método.

  1. No es necesario inicializar el valor en la función de llamada.
  2. Debe asignar el valor en la función llamada, de lo contrario el compilador informará un error.

árbitro:

En C #, cuando pasa un tipo de valor como int, float, double, etc. como argumento al parámetro del método, se pasa por valor. Por lo tanto, si modifica el valor del parámetro, no afecta el argumento en la llamada al método. Pero si marca el parámetro con la palabra clave "ref", se reflejará en la variable real.

  1. Debe inicializar la variable antes de llamar a la función.
  2. No es obligatorio asignar ningún valor al parámetro ref en el método. Si no cambia el valor, ¿cuál es la necesidad de marcarlo como "ref"?

Estoy creando una función en la que necesito pasar un objeto para que pueda ser modificado por la función. Cuál es la diferencia entre:

public void myFunction(ref MyClass someClass)

y

public void myFunction(out MyClass someClass)

¿Qué debo usar y por qué?


"Panadero"

Esto se debe a que la primera cambia la referencia de cadena para que apunte a "Baker". Es posible cambiar la referencia porque la pasó a través de la palabra clave ref (=> una referencia a una referencia a una cadena). La segunda llamada obtiene una copia de la referencia a la cadena.

La cuerda parece una especie de especial al principio. Pero la cadena es solo una clase de referencia y si la define

string s = "Able";

entonces s es una referencia a una clase de cadena que contiene el texto "Able"! Otra asignación a la misma variable vía

s = "Baker";

no cambia la cadena original, solo crea una nueva instancia y vamos a apuntar a esa instancia!

Puedes probarlo con el siguiente pequeño código de ejemplo:

string s = "Able"; string s2 = s; s = "Baker"; Console.WriteLine(s2);

¿Qué esperas? Lo que obtendrás es todavía "Able" porque simplemente estableciste la referencia en s en otra instancia, mientras que s2 apunta a la instancia original.

EDIT: la cadena también es inmutable, lo que significa que simplemente no hay ningún método o propiedad que modifique una instancia de cadena existente (puede intentar encontrar una en los documentos pero no encontrará ninguna :-)). ¡Todos los métodos de manipulación de cadenas devuelven una nueva instancia de cadena! (Es por eso que a menudo obtienes un mejor rendimiento cuando usas la clase StringBuilder)


A continuación he mostrado un ejemplo utilizando tanto Ref como out . Ahora, todos ustedes serán aclarados acerca de la referencia y la salida.

En el siguiente ejemplo mencionado, cuando comento // myRefObj = new myClass {Name = "ref outside called !!"}; línea, recibirá un error que dice "Uso de la variable local no asignada ''myRefObj''" , pero no existe tal error.

Dónde usar Ref : cuando estamos llamando a un procedimiento con un parámetro in y el mismo parámetro se utilizará para almacenar la salida de ese proc.

Dónde usar Out: cuando estamos llamando a un procedimiento sin parámetro in y se utilizará el mismo parámetro para devolver el valor de ese proc. También tenga en cuenta la salida

public partial class refAndOutUse : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { myClass myRefObj; myRefObj = new myClass { Name = "ref outside called!! <br/>" }; myRefFunction(ref myRefObj); Response.Write(myRefObj.Name); //ref inside function myClass myOutObj; myOutFunction(out myOutObj); Response.Write(myOutObj.Name); //out inside function } void myRefFunction(ref myClass refObj) { refObj.Name = "ref inside function <br/>"; Response.Write(refObj.Name); //ref inside function } void myOutFunction(out myClass outObj) { outObj = new myClass { Name = "out inside function <br/>" }; Response.Write(outObj.Name); //out inside function } } public class myClass { public string Name { get; set; } }


Dado que está pasando un tipo de referencia (una clase), no es necesario usar ref porque, por defecto, solo se pasa una referencia al objeto real y, por lo tanto, siempre se cambia el objeto detrás de la referencia.

Ejemplo:

public void Foo() { MyClass myObject = new MyClass(); myObject.Name = "Dog"; Bar(myObject); Console.WriteLine(myObject.Name); // Writes "Cat". } public void Bar(MyClass someObject) { someObject.Name = "Cat"; }

Mientras pase una clase, no tiene que usar ref si desea cambiar el objeto dentro de su método.


Desde el punto de vista de un método que recibe un parámetro, la diferencia entre ref y out es que C # requiere que los métodos escriban en cada parámetro de out antes de regresar, y no deben hacer nada con ese parámetro, aparte de pasarlo como un parámetro de out . o escribiéndolo, hasta que se haya pasado como parámetro de out a otro método o se haya escrito directamente. Tenga en cuenta que algunos otros idiomas no imponen tales requisitos; un método virtual o de interfaz que se declara en C # con un parámetro de out puede ser anulado en otro idioma que no imponga ninguna restricción especial en dichos parámetros.

Desde el punto de vista de la persona que llama, en muchas circunstancias C # asumirá que cuando se llama a un método con un parámetro de out , la variable pasada se escribe sin haber sido leída primero. Esta suposición puede no ser correcta al llamar a métodos escritos en otros idiomas. Por ejemplo:

struct MyStruct { ... myStruct(IDictionary<int, MyStruct> d) { d.TryGetValue(23, out this); } }

Si myDictionary identifica una IDictionary<TKey,TValue> escrita en un lenguaje distinto de C #, aunque MyStruct s = new MyStruct(myDictionary); Parece una tarea, potencialmente podría dejar s sin modificar.

Tenga en cuenta que los constructores escritos en VB.NET, a diferencia de los de C #, no hacen suposiciones sobre si los métodos llamados modificarán los parámetros y eliminarán todos los campos de manera incondicional. El comportamiento extraño al que se alude anteriormente no ocurrirá con el código escrito completamente en VB o completamente en C #, pero puede ocurrir cuando el código escrito en C # llama a un método escrito en VB.NET.


Digamos que Dom aparece en el cubículo de Peter sobre la nota sobre los informes de TPS.

Si Dom fuera un argumento de referencia, tendría una copia impresa de la nota.

Si Dom estuviera fuera de discusión, haría que Peter imprimiera una nueva copia de la nota para que se la llevara.


El modificador de ref significa que:

  1. El valor ya está establecido y
  2. El método puede leerlo y modificarlo.

El modificador de out significa que:

  1. El valor no está establecido y el método no puede leerlo hasta que se establezca.
  2. El método debe configurarlo antes de volver.

Estaba jugando con el ref y encontré este ejemplo bastante interesante. Pensé la llamada de RefEater(ref s1); provocará un error de compilación como en el segundo caso comentado, pero el campo s1 se inicializa a su valor predeterminado antes de llamar al constructor ( https://.com/a/1920659/5612780 ).

public class Class1 { // this will have the default value private string s1; public Class1() { // no issue here.. RefEater(ref s1); // Error CS0165 Use of unassigned local variable ''s2'' //string s2; //RefEater(ref s2); } private void RefEater(ref string s) { } }


Extendiendo el ejemplo del perro, el gato. El segundo método con ref cambia el objeto referenciado por el llamante. De ahí el "gato" !!!

public static void Foo() { MyClass myObject = new MyClass(); myObject.Name = "Dog"; Bar(myObject); Console.WriteLine(myObject.Name); // Writes "Dog". Bar(ref myObject); Console.WriteLine(myObject.Name); // Writes "Cat". } public static void Bar(MyClass someObject) { MyClass myTempObject = new MyClass(); myTempObject.Name = "Cat"; someObject = myTempObject; } public static void Bar(ref MyClass someObject) { MyClass myTempObject = new MyClass(); myTempObject.Name = "Cat"; someObject = myTempObject; }


Para aquellos que aprenden con el ejemplo (como yo), esto es lo que Anthony Kolesov está diciendo .

He creado algunos ejemplos mínimos de ref, out y otros para ilustrar el punto. No estoy cubriendo las mejores prácticas, solo ejemplos para entender las diferencias.

https://gist.github.com/2upmedia/6d98a57b68d849ee7091


Puede que no sea tan bueno en esto, pero seguramente las cadenas (aunque son técnicamente tipos de referencia y viven en el montón) se pasan por valor, no por referencia.

string a = "Hello"; string b = "goodbye"; b = a; //attempt to make b point to a, won''t work. a = "testing"; Console.WriteLine(b); //this will produce "hello", NOT "testing"!!!!

Esta es la razón por la que necesita ref si desea que existan cambios fuera del alcance de la función que los genera, de lo contrario no está pasando una referencia.

Por lo que sé, solo necesita ref para los tipos de estructura / valor y la cadena en sí misma, ya que la cadena es un tipo de referencia que pretende serlo pero no es un tipo de valor.

Aunque podría estar completamente equivocado aquí, soy nuevo.


Ref: la palabra clave ref se utiliza para pasar un argumento como referencia. Esto significa que cuando el valor de ese parámetro se cambia en el método, se refleja en el método de llamada. Un argumento que se pasa utilizando una palabra clave ref debe inicializarse en el método de llamada antes de pasar al método llamado.

Out: la palabra clave out también se utiliza para pasar un argumento como la palabra clave ref, pero el argumento puede pasarse sin asignarle ningún valor. Un argumento que se pasa utilizando una palabra clave out debe inicializarse en el método llamado antes de que vuelva al método de llamada.

public class Example { public static void Main() { int val1 = 0; //must be initialized int val2; //optional Example1(ref val1); Console.WriteLine(val1); Example2(out val2); Console.WriteLine(val2); } static void Example1(ref int value) { value = 1; } static void Example2(out int value) { value = 2; } } /* Output 1 2

Ref y out en sobrecarga de métodos.

Tanto la referencia como la salida no se pueden usar en la sobrecarga de métodos simultáneamente. Sin embargo, ref y out se tratan de manera diferente en tiempo de ejecución, pero se tratan igual en tiempo de compilación (CLR no diferencia entre los dos, mientras que creó IL para ref y out).


Si desea pasar su parámetro como referencia, debe inicializarlo antes de pasar el parámetro a la función. El compilador mostrará el error. Pero en caso de que no haya un parámetro, no necesita inicializar el parámetro objeto antes de pasarlo a la Método. Puede inicializar el objeto en el propio método de llamada.


Son prácticamente iguales: la única diferencia es que una variable que se pasa como parámetro de salida no necesita inicializarse, y el método que usa el parámetro ref tiene que configurarlo en algo.

int x; Foo(out x); // OK int y; Foo(ref y); // Error

Los parámetros de referencia son para datos que pueden modificarse, y los parámetros de salida son para datos que son una salida adicional para la función (por ejemplo, int.TryParse) que ya están usando el valor de retorno para algo.


Tenga en cuenta que el parámetro de referencia que se pasa dentro de la función se trabaja directamente.

Por ejemplo,

public class MyClass { public string Name { get; set; } } public void Foo() { MyClass myObject = new MyClass(); myObject.Name = "Dog"; Bar(myObject); Console.WriteLine(myObject.Name); // Writes "Dog". } public void Bar(MyClass someObject) { MyClass myTempObject = new MyClass(); myTempObject.Name = "Cat"; someObject = myTempObject; }

Esto escribirá Dog, no Cat. Por lo tanto, debe trabajar directamente en someObject.


Voy a probar mi mano en una explicación:

Creo que entendemos cómo funcionan los tipos de valor, ¿no? Los tipos de valor son (int, long, struct, etc.). Cuando los envía a una función sin un comando ref, COPIAS los datos . Todo lo que hagas con esos datos en la función solo afecta a la copia, no al original. El comando ref envía los datos ACTUALES y cualquier cambio afectará los datos fuera de la función.

Bien a la parte confusa, tipos de referencia:

Permite crear un tipo de referencia:

List<string> someobject = new List<string>()

Cuando creas un objeto nuevo, se crean dos partes:

  1. El bloque de memoria que contiene datos para algún objeto .
  2. Una referencia (puntero) a ese bloque de datos.

Ahora, cuando envía algún objeto a un método sin ref, COPIAS el puntero de referencia , NO los datos. Así que ahora tienes esto:

(outside method) reference1 => someobject (inside method) reference2 => someobject

Dos referencias apuntando al mismo objeto. Si modifica una propiedad en algún objeto utilizando reference2, afectará a los mismos datos apuntados por reference1.

(inside method) reference2.Add("SomeString"); (outside method) reference1[0] == "SomeString" //this is true

Si anula la referencia2 o la apunta a datos nuevos, no afectará a la referencia1 ni a la referencia de datos1.

(inside method) reference2 = new List<string>(); (outside method) reference1 != null; reference1[0] == "SomeString" //this is true The references are now pointing like this: reference2 => new List<string>() reference1 => someobject

Ahora, ¿qué sucede cuando envías algún objeto por ref a un método? La referencia real a algún objeto se envía al método. Así que ahora solo tienes una referencia a los datos:

(outside method) reference1 => someobject; (inside method) reference1 => someobject;

Pero ¿qué significa esto? Actúa exactamente igual que enviar algún objeto, no por ref, excepto por dos cosas principales:

1) Cuando anula la referencia dentro del método, anulará la que está fuera del método.

(inside method) reference1 = null; (outside method) reference1 == null; //true

2) Ahora puede apuntar la referencia a una ubicación de datos completamente diferente y la referencia fuera de la función ahora apuntará a la nueva ubicación de datos.

(inside method) reference1 = new List<string>(); (outside method) reference1.Count == 0; //this is true


ref y out funcionan igual que pasar por referencias y pasar por punteros como en C ++.

Para ref, el argumento debe declararse e inicializarse.

Para fuera, el argumento debe declararse pero puede o no puede ser inicializado

double nbr = 6; // if not initialized we get error double dd = doit.square(ref nbr); double Half_nbr ; // fine as passed by out, but inside the calling method you initialize it doit.math_routines(nbr, out Half_nbr);



ref le dice al compilador que el objeto se inicializa antes de ingresar a la función, mientras que out le dice al compilador que el objeto se inicializará dentro de la función.

Entonces, mientras que la ref es de dos vías, la out es solo de salida.


ref y out comportan de manera similar, excepto las siguientes diferencias.

  • ref variable ref debe inicializarse antes de su uso. out variable out puede ser usada sin asignación
  • out parámetro out debe tratarse como un valor no asignado por la función que lo utiliza. Por lo tanto, podemos usar out parámetro inicializado en el código de llamada, pero el valor se perderá cuando se ejecute la función.

Fuera: se puede usar una instrucción de devolución para devolver solo un valor de una función. Sin embargo, utilizando parámetros de salida, puede devolver dos valores de una función. Los parámetros de salida son como parámetros de referencia, excepto que transfieren datos fuera del método y no a él.

El siguiente ejemplo lo ilustra:

using System; namespace CalculatorApplication { class NumberManipulator { public void getValue(out int x ) { int temp = 5; x = temp; } static void Main(string[] args) { NumberManipulator n = new NumberManipulator(); /* local variable definition */ int a = 100; Console.WriteLine("Before method call, value of a : {0}", a); /* calling a function to get the value */ n.getValue(out a); Console.WriteLine("After method call, value of a : {0}", a); Console.ReadLine(); } } }

ref: Un parámetro de referencia es una referencia a una ubicación de memoria de una variable. Cuando pasa parámetros por referencia, a diferencia de los parámetros de valor, no se crea una nueva ubicación de almacenamiento para estos parámetros. Los parámetros de referencia representan la misma ubicación de memoria que los parámetros reales que se suministran al método.

En C #, declara los parámetros de referencia usando la palabra clave ref. El siguiente ejemplo demuestra esto:

using System; namespace CalculatorApplication { class NumberManipulator { public void swap(ref int x, ref int y) { int temp; temp = x; /* save the value of x */ x = y; /* put y into x */ y = temp; /* put temp into y */ } static void Main(string[] args) { NumberManipulator n = new NumberManipulator(); /* local variable definition */ int a = 100; int b = 200; Console.WriteLine("Before swap, value of a : {0}", a); Console.WriteLine("Before swap, value of b : {0}", b); /* calling a function to swap the values */ n.swap(ref a, ref b); Console.WriteLine("After swap, value of a : {0}", a); Console.WriteLine("After swap, value of b : {0}", b); Console.ReadLine(); } } }


Tiempo de autoría:

(1) Creamos el método de llamada Main()

(2) crea un objeto de lista (que es un objeto de tipo de referencia) y lo almacena en la variable myList .

public sealed class Program { public static Main() { List<int> myList = new List<int>();

Durante el tiempo de ejecución:

(3) Runtime asigna una memoria en la pila en el # 00, lo suficientemente amplia como para almacenar una dirección (# 00 = myList , ya que los nombres de las variables son en realidad solo alias para las ubicaciones de memoria)

(4) Runtime crea un objeto de lista en el montón en la ubicación de memoria #FF (todas estas direcciones son, por ejemplo, sakes)

(5) El tiempo de ejecución luego almacenaría la dirección de inicio #FF del objeto en # 00 (o en palabras, almacena la referencia del objeto List en la lista myList punteros)

Volver al tiempo de autoría:

(6) A continuación, pasamos el objeto List como argumento myParamList al método modifyMyList llamado y le asignamos un nuevo objeto List.

List<int> myList = new List<int>(); List<int> newList = ModifyMyList(myList) public List<int> ModifyMyList(List<int> myParamList){ myParamList = new List<int>(); return myParamList; }

Durante el tiempo de ejecución:

(7) Runtime inicia la rutina de llamada para el método llamado y, como parte de él, verifica el tipo de parámetros.

(8) Al encontrar el tipo de referencia, asigna una memoria en la pila en el # 04 para myParamList alias de la variable de parámetro myParamList .

(9) Entonces también almacena el valor #FF en él.

(10) Runtime crea un objeto de lista en el montón en la ubicación de memoria # 004 y reemplaza #FF en # 04 con este valor (o hace referencia al objeto de lista original y señala al nuevo objeto de lista en este método)

La dirección en # 00 no se altera y conserva la referencia a #FF (o el puntero original de myList no está alterado).

La palabra clave ref es una directiva de compilación para omitir la generación de código de tiempo de ejecución para (8) y (9), lo que significa que no habrá asignación de almacenamiento dinámico para los parámetros del método. Utilizará el puntero original # 00 para operar en el objeto en #FF. Si el puntero original no está inicializado, el tiempo de ejecución detendrá las quejas de que no puede continuar ya que la variable no está inicializada

La palabra clave out es una directiva de compilación que es prácticamente lo mismo que ref con una ligera modificación en (9) y (10). El compilador espera que el argumento no esté inicializado y continuará con (8), (4) y (5) para crear un objeto en el montón y para almacenar su dirección de inicio en la variable argumento. No se lanzará ningún error no inicializado y se perderá cualquier referencia previa almacenada.


ref significa que el valor en el parámetro ref ya está establecido, el método puede leerlo y modificarlo. Usar la palabra clave ref es lo mismo que decir que la persona que llama es responsable de inicializar el valor del parámetro.

out le dice al compilador que la inicialización del objeto es responsabilidad de la función, la función tiene que asignarse al parámetro out. No está permitido dejarlo sin asignar.


public static void Main(string[] args) { //int a=10; //change(ref a); //Console.WriteLine(a); // Console.Read(); int b; change2(out b); Console.WriteLine(b); Console.Read(); } // static void change(ref int a) //{ // a = 20; //} static void change2(out int b) { b = 20; }

puede verificar este código; le describirá su diferencia completa cuando use "ref" significa que ya ha inicializado ese int / string

pero cuando usas "out" funciona en ambas condiciones si u inicializa int / string o no, pero debes inicializar int / string en esa función