C# 7.0 – Specification – Ref returns and Ref locals
En versiones previas a C# 7.0, podíamos pasar cosas por referencia.
Esto lo podíamos hacer utilizando el modificador ref.
En C# 7.0, además de poder seguir utilizando ese mecanismo, podemos ahora devolverlas por referencia, y almacenarlas por referencia en variables locales.
El uso de matrices y estructuras aquí, tendría sentido, y esto permite entre otras cosa, evitar asignaciones de memoria, evitando que el Garbage Collector trabaje en exceso.
Desde un punto de vista práctico, en C# 7.0 podemos hacer por lo tanto algo parecido a esto:
private class Person { public string Name { get; set; } public int Age { get; set; } } private static void RefReturnsAndLocals() { var people = new Person[] { new Person() { Name = "Charles", Age = 19 }, new Person() { Name = "Mary", Age = 24 } }; try { ref Person person = ref GetPersonBy("Mary", people); Console.WriteLine($"{person.Name} is {person.Age} years old"); ref Person personThrowException = ref GetPersonBy("Aaa", people); Console.WriteLine($"{personThrowException.Name} is {personThrowException.Age} years old"); } catch (Exception ex) { Console.WriteLine(ex.Message); } } private static ref Person GetPersonBy(string name, Person[] people) { if (people.Where(a => a.Name == name).SingleOrDefault() == null) { throw new IndexOutOfRangeException($"{nameof(name)} {name} not found"); } var position = people.Select((Value, Index) => new { Value, Index }).Single(p => p.Value.Name == name); return ref people[position.Index]; }
Como podemos ver, el uso de ref es ligeramente diferente al que estábamos acostumbrados, si bien, ofrece las mejoras indicadas anteriormente.
En el caso de return ref people[0]; lo que se devuelve es la localización del valor o variable almacenada, no el valor en sí.
No obstante, al ser un valor por referencia, debemos tener en cuenta que como apunta al valor, si el array o matriz cambiara, el resultado podría sufrir variaciones no esperadas.
De hecho, el siguiente código, tiene un resultado diferente al anterior:
private static void RefReturnsAndLocals() { var people = new Person[] { new Person() { Name = "Charles", Age = 19 }, new Person() { Name = "Mary", Age = 24 } }; try { ref Person person = ref GetPersonBy("Mary", people); people[1].Age = 12; Console.WriteLine($"{person.Name} is {person.Age} years old"); ref Person personThrowException = ref GetPersonBy("Aaa", people); Console.WriteLine($"{personThrowException.Name} is {personThrowException.Age} years old"); } catch (Exception ex) { Console.WriteLine(ex.Message); } }
En negrita y en rojo, he indicado la línea en la que se modifica el valor de la matriz y que tiene person, por lo que ese valor queda reemplazado al ser un tipo por referencia.
¡Happy Coding!