Tengo un objeto que está en mi estado de memoria del programa y también tengo algunas otras funciones de trabajo a las que paso el objeto para modificar el estado. Lo he estado pasando por referencia a las funciones de trabajador. Sin embargo, encontré la siguiente función.
byte[] received_s = new byte[2048];
IPEndPoint tmpIpEndPoint = new IPEndPoint(IPAddress.Any, UdpPort_msg);
EndPoint remoteEP = (tmpIpEndPoint);
int sz = soUdp_msg.ReceiveFrom(received_s, ref remoteEP);
Me confunde porque ambos received_s
y remoteEP
están devolviendo cosas de la función. ¿Por qué remoteEP
necesita un ref
y received_s
no?
También soy programador de corriente alterna, así que tengo problemas para sacarme los punteros de la cabeza.
Editar: Parece que los objetos en C # son punteros al objeto debajo del capó. Entonces, cuando pasa un objeto a una función, puede modificar el contenido del objeto a través del puntero y lo único que se pasa a la función es el puntero al objeto para que el objeto en sí no se esté copiando. Use ref o out si desea poder cambiar o crear un nuevo objeto en la función que es como un puntero doble.
if (int.TryParse(text, out int value)) { ... use value here ... }
Piense en un parámetro no ref como un puntero y un parámetro ref como un puntero doble. Esto me ayudó más.
Casi nunca debería pasar valores por ref. Sospecho que si no fuera por problemas de interoperabilidad, el equipo de .Net nunca lo habría incluido en la especificación original. La forma OO de lidiar con la mayoría de los problemas que resuelven los parámetros de referencia es:
Para múltiples valores de retorno
Para primitivas que cambian en un método como resultado de la llamada al método (el método tiene efectos secundarios en los parámetros primitivos)
fuente
IPAddress.TryParse(string, out IPAddress)
.if (int.TryParse("123", out var theInt) { /* use theInt */ }
tuviéramosvar candidate = int.TrialParse("123"); if (candidate.Parsed) { /* do something with candidate.Value */ }
más código, pero es mucho más consistente con el diseño del lenguaje C #.Probablemente podría escribir una aplicación C # completa y nunca pasar ningún objeto / estructura por ref.
Tuve un profesor que me dijo esto:
Estoy de acuerdo con su consejo, y en mis más de cinco años desde la escuela, nunca lo he necesitado más allá de llamar al Framework o la API de Windows.
fuente
SetName(person, "John Doe")
, la propiedad del nombre cambiará y ese cambio se reflejará en la persona que llama.Dado queived_s es una matriz, está pasando un puntero a esa matriz. La función manipula los datos existentes en su lugar, sin cambiar la ubicación o el puntero subyacentes. La palabra clave ref significa que está pasando el puntero real a la ubicación y actualizando ese puntero en la función exterior, por lo que el valor en la función exterior cambiará.
Por ejemplo, la matriz de bytes es un puntero a la misma memoria antes y después, la memoria se acaba de actualizar.
La referencia de punto final en realidad está actualizando el puntero al punto final en la función exterior a una nueva instancia generada dentro de la función.
fuente
Piense en una referencia como lo que significa que está pasando un puntero por referencia. No usar una referencia significa que está pasando un puntero por valor.
Mejor aún, ignore lo que acabo de decir (probablemente sea engañoso, especialmente con los tipos de valor) y lea esta página de MSDN .
fuente
Tengo entendido que todos los objetos derivados de la clase Object se pasan como punteros, mientras que los tipos ordinarios (int, struct) no se pasan como punteros y requieren ref. No estoy seguro de la cadena (¿se deriva en última instancia de la clase Object?)
fuente
Si bien estoy de acuerdo con la respuesta de Jon Skeet en general y algunas de las otras respuestas, hay un caso de uso para usar
ref
, y es para ajustar las optimizaciones de rendimiento. Se ha observado durante la elaboración de perfiles de rendimiento que establecer el valor de retorno de un método tiene ligeras implicaciones de rendimiento, mientras que el usoref
como argumento mediante el cual el valor de retorno se completa en ese parámetro da como resultado la eliminación de este pequeño cuello de botella.Esto realmente solo es útil cuando los esfuerzos de optimización se llevan a niveles extremos, sacrificando la legibilidad y tal vez la capacidad de prueba y el mantenimiento para ahorrar milisegundos o quizás milisegundos divididos.
fuente
Primero, la regla de la zona cero, las primitivas se pasan por valor (pila) y las no primitivas por referencia (montón) en el contexto de los TIPOS involucrados.
Los parámetros involucrados se pasan por Valor por defecto. Buen post que explica las cosas en detalle. http://yoda.arachsys.com/csharp/parameters.html
Podemos decir (con advertencia) Los tipos no primitivos no son más que punteros Y cuando los pasamos por ref podemos decir que estamos pasando Double Pointer
fuente