Por que o C # não suporta o retorno de referências?

Eu li que .NET suporta retorno de referências, mas C # não. Existe um motivo especial? Por que não posso fazer algo como:

static ref int Max(ref int x, ref int y) { if (x > y) return ref x; else return ref y; } 

Esta questão foi o assunto do meu blog em 23 de junho de 2011 . Obrigado pela ótima pergunta!

A equipe do C # está considerando isso para o C # 7. Consulte https://github.com/dotnet/roslyn/issues/5233 para obter detalhes.

ATUALIZAÇÃO: O recurso chegou ao C # 7!


Você está certo; O .NET suporta methods que retornam referências gerenciadas a variables. O .NET também suporta variables ​​locais que contêm referências gerenciadas para outras variables. (Observe, no entanto, que o .NET não oferece suporte a campos ou matrizes que contenham referências gerenciadas a outras variables, pois isso complica muito a história da garbage collection. Além disso, os tipos “referência gerenciada à variável” não podem ser convertidos em object e, portanto, não podem ser usados ​​como digite argumentos para tipos ou methods genéricos.)

Comentador “RPM1984” por algum motivo pediu uma citação para este fato. RPM1984 Recomendo que você leia a especificação CLI Partition I Seção 8.2.1.1, “Managed pointer and related types” para obter informações sobre esse recurso do .NET.

É perfeitamente possível criar uma versão do C # que suporte esses dois resources. Você poderia então fazer coisas como

 static ref int Max(ref int x, ref int y) { if (x > y) return ref x; else return ref y; } 

e depois ligue para ele

 int a = 123; int b = 456; ref int c = ref Max(ref a, ref b); c += 100; Console.WriteLine(b); // 556! 

Eu sei empiricamente que é possível construir uma versão do C # que suporte esses resources porque eu fiz isso . Programadores avançados, particularmente pessoas portando código C ++ não gerenciado, frequentemente nos pedem mais capacidade de fazer coisas com referências sem ter que sair do problema de realmente usar pointers e fixar memory em todo lugar. Usando referências gerenciadas, você obtém esses benefícios sem pagar o custo de estragar seu desempenho de garbage collection.

Consideramos esse recurso e implementamos o suficiente para mostrar a outras equipes internas a obtenção de feedback. No entanto, neste momento, com base em nossa pesquisa , acreditamos que o recurso não possui apelo suficientemente amplo ou casos de uso convincentes para torná-lo um recurso real de idioma suportado . Temos outras prioridades mais altas e uma quantidade limitada de tempo e esforço disponíveis, por isso não faremos esse recurso tão cedo.

Além disso, fazê-lo corretamente exigiria algumas alterações no CLR. No momento, o CLR trata os methods de retorno de retorno como legais, mas não verificáveis, porque não temos um detector que detecte essa situação:

 ref int M1(ref int x) { return ref x; } ref int M2() { int y = 123; return ref M1(ref y); // Trouble! } int M3() { ref int z = ref M2(); return z; } 

M3 retorna o conteúdo da variável local do M2, mas o tempo de vida dessa variável terminou! É possível escrever um detector que determine os usos de retornos que claramente não violem a segurança da pilha. O que faríamos é escrever um detector desse tipo e, se o detector não pudesse provar a segurança da pilha, não permitiríamos o uso de retornos de referência nessa parte do programa. Não é uma enorme quantidade de trabalho dev para fazê-lo, mas é muito difícil para as equipes de teste garantir que realmente tenhamos todos os casos. É apenas mais uma coisa que aumenta o custo do recurso até o ponto em que, no momento, os benefícios não superam os custos.

Se você pode descrever para mim porque é que você quer esse recurso, eu realmente aprecio isso . Quanto mais informações obtivermos de clientes reais sobre o motivo pelo qual eles querem, mais provável será que ele chegue ao produto algum dia. É um pequeno recurso bonitinho e eu gostaria de poder levá-lo aos clientes de alguma forma, se houver interesse suficiente.

(Veja também questões relacionadas É possível retornar uma referência para uma variável em C #? E Posso usar uma referência dentro de uma function c # como C ++? )

Você está falando sobre methods que retornam uma referência a um tipo de valor. O único exemplo interno em C # que conheço é o array-accessor de um tipo de valor:

 public struct Point { public int X { get; set; } public int Y { get; set; } } 

e agora crie um array dessa estrutura:

 var points = new Point[10]; points[0].X = 1; points[0].Y = 2; 

Nesse caso, points[0] , o indexador de matriz, está retornando uma referência para struct. É impossível escrever seu próprio indexador (por exemplo, para uma coleção personalizada), que possui o mesmo comportamento “retornar uma referência”.

Eu não criei a linguagem C #, então eu não conheço todo o raciocínio por trás de não suportá-la, mas acho que a resposta curta pode ser: podemos nos dar muito bem sem ela.

Você sempre pode fazer algo como:

 public delegate void MyByRefConsumer(ref T val); public void DoSomethingWithValueType(MyByRefConsumer c) { int x = 2; c(ref x); //Handle potentially changed x... } 

C # 7.0 tem suporte para retornar referências. Veja minha resposta aqui .