Para muitos desenvolvedores, especialmente aqueles que estão construindo jogos ou analisando dados numéricos, o aspecto de desempenho é tratado com grande ênfase. E para estes desenvolvedores, nada é mais problemático do que alocação de memória. Enquanto a alocação de memória para alguns objetos é uma tarefa com pouco custo do ponto de vista computacional, a realização de muitas alocações adiciona pressão à memória e causa ciclos de coleta de lixo (garbage collection) mais frequentes.
A memória alocada no Heap também pode causar problemas para o cache. Se houver uma lista ou uma matriz (array) de tipos de referência, seus dados são armazenados separadamente da matriz. Isto significa que haverá desperdício de áreas de cache separadas para a matriz e para os objetos referenciados pela matriz. E se estes objetos foram criados ao mesmo tempo, eles podem estar espalhados na memória que talvez sejam necessárias novas áreas de cache. Este espalhamento de dados relacionados é conhecido como localização pobre (poor locality).
A utilização de tipos de valores (structs na terminologia C#) pode reduzir dramaticamente o número de alocações e melhorar a localização. Entretanto, existem limitações no que se pode fazer com tipos de valores. Como eles são projetados para serem copiados na atribuição (copy-on-assignement), é necessário manter estas estruturas com tamanho pequeno ou pode haver o risco de um sério problema de desempenho, o que invalidaria a razão de utilizá-las.
Uma maneira de reduzir o número de cópias de valores desnecessários é através da passagem de tipos de valor para funções utilizando um ponteiro gerenciado. Atualmente, a única forma de criar um ponteiro gerenciado em C# é utilizando a palavra reservada 'ref' como parte do parâmetro. Enquanto esta abordagem endereça o desempenho em alguns cenários, o CLR (Common Language Runtime) é capaz de fazer muito mais com ponteiros gerenciados.
Na proposta Ref Returns and Locals, são apresentadas mais duas opções para os desenvolvedores C#.
Ref Local
Assumindo que a é uma variável local do tipo int, a proposta sugere a criação de uma variável local por referência (Ref Local) com esta sintaxe:
ref int x = a;
Assim como um parâmetro por referência (ref parameter), uma variável local por referência (ref local) torna-se efetivamente um sinônimo para a variável local indicada, eliminando a necessidade de realizar uma cópia. Também é possível utilizá-la para obter um ponteiro para um elemento de uma matriz ou para um campo em outro objeto.
ref int y = b[2]; ref int z = c.d;
Nos termos do CLR, uma variável local por referência é chamada "TypedReference". Um "TypedReferece" contém o ponteiro para a localização na memória e a informação sobre que tipo de dado deve estar armazenado nesta localização.
Como regra, um TypedReference é sempre um parâmetro ou variável local. Isto é necessário, pois o CLR não permite que itens do heap apontem para o interior de outros itens no heap. Também não é possível retornar um TypedReference, já que isso tornaria possível retornar uma referência para um valor local que obviamente não existiria após a saída de um método.
Ref Return
A segunda parte da proposta sugere o retorno de um tipo de referência a partir de uma função. Isto permitiria cenários como:
public static ref TValue Choose(Func condition, ref TValue left, ref TValue right) { return condition() ? ref left : ref right; } Matrix3D left = […], right = […]; Choose(chooser, ref left, ref right).M20 = 1.0;
Com esta nova sintaxe, não há cópias da estrutura em nenhum ponto do exemplo apresentado. Ao invés disso, utilizam-se ponteiros gerenciados.
De forma distinta de uma variável local por referência, a implementação desta funcionalidade pode requerer alterações no padrão do CLR. Como já mencionado anteriormente, retornar um TypedReference é algo normalmente não permitido. Tecnicamente falando é possível fazer, mas esta prática é considerada como uma prática de tipagem insegura (not type-safe) e portanto não verificável. A utilização de código não verificável não é permitida em ambientes com configurações de segurança restrita e introduz o risco de graves defeitos que normalmente só são encontrados em código C/C++.
Para mitigar este risco, parte da proposta descreve que só pode retornar uma referência para algo no heap ou para um parâmetro ref/out já existente. Em outras palavras, o compilador verificaria que não pode retornar uma referência para uma variável local.