Continuando com a série de artigos sobre novidades do C# 7, hoje conheceremos o Ref Returns.
Passagem por valor e por referência
Desde de o seu início, o C# possui duas formas de passagem de variáveis para um método, por valor e por referência.
Curso C# (C Sharp) Básico
Conhecer o cursoPassagem por valor significa que apenas o valor da variável será passado para o método. Caso este valor seja alterado dentro do método, isso não irá refletir na variável passada:
static void Main(string[] args)
{
int i = 10;
PassagemPorValor(i);
Console.WriteLine($"Após chamar o método, {nameof(i)} = {i}");
}
static void PassagemPorValor(int j)
{
j = 20;
}
Já na passagem por referência, é passada a referência da variável para o método. Ou seja, é passado o endereço da memória, assim, dentro desse contexto, caso ela seja alterada, isso será refletido na variável passada:
static void Main(string[] args)
{
int i = 10;
PassagemPorValor(ref i);
Console.WriteLine($"Após chamar o método, {nameof(i)} = {i}");
}
static void PassagemPorValor(ref int j)
{
j = 20;
}
Você provavelmente já conhece essas duas formas de passagem de variáveis, pois isso é abordado (ou deveria ser) em todo curso básico da linguagem.
É necessário revisar este ponto, pois uma coisa precisa ficar bem clara: quando o ref
é utilizado, trabalha-se com a referência da variável, o seu espaço de memória. Podemos até dizer que ref
funciona como os ponteiros de C/C++ (para quem conhece).
Ref Local
Antes de vermos a parte principal deste artigo, é bom mencionar que agora no C# 7, o ref
pode ser utilizado na declaração de uma variável:
int i = 1;
ref int j = ref i;
j = 2;
Console.WriteLine($"A variável {nameof(i)} foi alterada para: {i}");
Assim como na passagem por referência, a variável j
está recebendo o endereço de memória de i
. Dessa forma, quando o valor de j
for alterado, o valor de i
também será.
Ref Return
O último recurso que o C# 7 adicionou ao ref
foi a possibilidade de retornar a referência de uma variável.
Vamos a um exemplo para ficar mais claro:
public class Exemplo
{
private int variavel = 0;
public int ObterValor() => variavel;
public ref int ObterReferencia()
{
return ref variavel;
}
}
Note que dentro do método ObterReferencia
o método está retornando à referência da variável:
return ref variavel;
Curso C# (C Sharp) Intermediário
Conhecer o cursoAssim, quem chamar este método para utilizar uma variável Ref Local para armazenar a referência retornada e modificar o valor da variável:
var exemplo = new Exemplo();
ref int referencia = exemplo.ObterReferencia();
referencia++;
Console.WriteLine(exemplo.ObterValor());
Como as variáveis locais são removidas da memória quando o método é finalizado, não é possível aplicar o ref return em uma variável local:
public ref int RetornarPorReferencia()
{
int x = 10;
return ref x;
}
Mas, objetos que são armazenados na memória heap, como um array, podem ter suas referências retornadas, mesmo que eles sejam declarados dentro do método:
public ref int RetornarPorReferencia()
{
int[] arr = { 1, 2, 3, 4 };
return ref arr[0];
}
O código acima também poderia ser da seguinte forma:
public ref int RetornarPorReferencia()
{
int[] arr = { 1, 2, 3, 4 };
ref int x = ref arr[0];
return ref x;
}
Que o resultado seria o mesmo.
Por fim, um parâmetro passado por referência, pode ser retornado por referência:
public ref int RetornarPorReferencia(ref int x)
{
x = 2;
return ref x;
}
Curso C# (C Sharp) Avançado
Conhecer o cursoConclusão
Apesar de ser antigo na linguagem, o modificador ref
estava sendo subutilizado. Com os recursos ref local e ref return, ele ganha mais poder, permitindo que os programadores tenham acesso a memória, sem que isso torne a aplicação menos segura.
Mesmo sendo recursos úteis, há de se reconhecer que ref local e ref return são limitados a situações especificas. Então, caso você tenha um problema que se enquadre no seu uso, claro, não hesite em utilizá-lo.