Ter um debate amigável com um colega de trabalho sobre isso. Temos algumas ideias sobre isso, mas quer saber o que a multidão do SO pensa sobre isso?
Ter um debate amigável com um colega de trabalho sobre isso. Temos algumas ideias sobre isso, mas quer saber o que a multidão do SO pensa sobre isso?
Respostas:
Um dos motivos é que não há suporte CLR para um local somente leitura. Readonly é traduzido no opcode initonly CLR / CLI. Este sinalizador só pode ser aplicado a campos e não tem significado para um local. Na verdade, aplicá-lo a um local provavelmente produzirá um código não verificável.
Isso não significa que C # não possa fazer isso. Mas daria dois significados diferentes para a mesma construção de linguagem. A versão para locais não teria mapeamento equivalente de CLR.
readonly
palavra-chave para os campos precisa ser suportada pela CLI porque seu efeito é visível para outros assemblies. Significa apenas que a variável tem apenas uma atribuição no método em tempo de compilação.
const
(que em C ++ é mais parecido com C # do readonly
que com C # const
, embora possa desempenhar ambas as funções). Ainda assim, C ++ oferece suporte const
para variável automática local. Conseqüentemente, a falta de suporte CLR para um C # readonly
para variável local é irrelevante.
using
e out
estão fazendo exatamente isso e o mundo não entrou em colapso.
Acho que é um julgamento pobre por parte dos arquitetos C #. o modificador somente leitura em variáveis locais ajuda a manter a correção do programa (assim como afirma) e pode ajudar potencialmente o compilador a otimizar o código (pelo menos no caso de outras linguagens). O fato de não ser permitido no C # agora é outro argumento de que alguns dos "recursos" do C # são meramente uma imposição do estilo de codificação pessoal de seus criadores.
Respondendo à resposta de Jared, provavelmente teria que ser apenas um recurso de tempo de compilação - o compilador iria proibir você de escrever na variável após a declaração inicial (que teria que incluir uma atribuição).
Posso ver valor nisso? Potencialmente - mas não muito, para ser honesto. Se você não puder dizer facilmente se uma variável será ou não atribuída em outro lugar no método, então seu método é muito longo.
Pelo que vale a pena, Java tem esse recurso (usando o final
modificador) e muito raramente o vi usado, exceto nos casos em que tem que ser usado para permitir que a variável seja capturada por uma classe interna anônima - e onde ela está usado, dá-me a impressão de desordem em vez de informação útil.
readonly
/ final
valores de variáveis com suas palavras val
- var
chave e . No código Scala, os locais val
são usados com muita frequência (e são, de fato, preferidos aos locais var
). Suspeito que os principais motivos pelos quais o final
modificador não é usado com mais frequência em Java são a) desordem eb) preguiça.
readonly
não seria muito importante. Por outro lado, para variáveis locais que são usadas em encerramentos, readonly
em muitos casos deixariam o compilador gerar um código mais eficiente. Atualmente, quando a execução entra em um bloco que contém um fechamento, o compilador deve criar um novo objeto heap para as variáveis fechadas, mesmo se nenhum código que usaria o fechamento seja executado . Se uma variável fosse somente leitura, o código fora do encerramento poderia usar uma variável normal; apenas quando um delegado é criado para o encerramento ...
Uma proposta somente leitura de locais e parâmetros para foi brevemente discutida pela equipe de design do C # 7. De C # Design Meeting Notes para 21 de janeiro de 2015 :
Parâmetros e locais podem ser capturados por lambdas e, portanto, acessados simultaneamente, mas não há como protegê-los de problemas de estado mútuo compartilhado: eles não podem ser somente leitura.
Em geral, a maioria dos parâmetros e muitos locais nunca devem ser atribuídos depois de obterem seu valor inicial. Permitir somente leitura neles expressaria essa intenção claramente.
Um problema é que esse recurso pode ser um "incômodo atraente". Considerando que a "coisa certa" a fazer quase sempre seria tornar os parâmetros e locais somente leitura, isso desordenaria o código significativamente.
Uma ideia para aliviar parcialmente isso é permitir que a combinação somente leitura var em uma variável local seja contraída para val ou algo curto assim. De maneira mais geral, poderíamos tentar simplesmente pensar em uma palavra-chave mais curta do que a somente leitura estabelecida para expressar o somente leitura.
A discussão continua no repositório C # Language Design. Vote para mostrar seu apoio. https://github.com/dotnet/csharplang/issues/188
É um descuido para o designer da linguagem c #. F # tem a palavra-chave val e é baseada no CLR. Não há razão para que C # não tenha o mesmo recurso de linguagem.
Eu era aquele colega de trabalho e não era amigável! (só brincando)
Eu não eliminaria o recurso porque é melhor escrever métodos curtos. É um pouco como dizer que você não deve usar threads porque são difíceis. Dê-me a faca e deixe-me ser responsável por não me cortar.
Pessoalmente, eu queria outra palavra-chave do tipo "var" como "inv" (invariente) ou "rvar" para evitar confusão. Tenho estudado F # recentemente e acho a coisa imutável atraente.
Nunca soube que Java tinha isso.
Gostaria de variáveis locais somente leitura da mesma maneira que gosto de variáveis locais const . Mas tem menos prioridade do que outros tópicos.
Talvez sua prioridade seja a mesma razão para que os designers de C # (ainda!) Não implementem esse recurso. Mas deve ser fácil (e compatível com versões anteriores) suportar variáveis locais somente leitura em versões futuras.
Somente leitura significa que o único lugar em que a variável de instância pode ser definida é no construtor. Ao declarar uma variável localmente, ela não tem uma instância (está apenas no escopo) e não pode ser tocada pelo construtor.
Eu sei, isso não responde o porquê da sua pergunta. De qualquer forma, aqueles que estão lendo esta pergunta podem apreciar o código abaixo.
Se você está realmente preocupado em dar um tiro no próprio pé ao substituir uma variável local que deve ser definida apenas uma vez, e não quer torná-la uma variável mais acessível globalmente, você poderia fazer algo assim.
public class ReadOnly<T>
{
public T Value { get; private set; }
public ReadOnly(T pValue)
{
Value = pValue;
}
public static bool operator ==(ReadOnly<T> pReadOnlyT, T pT)
{
if (object.ReferenceEquals(pReadOnlyT, null))
{
return object.ReferenceEquals(pT, null);
}
return (pReadOnlyT.Value.Equals(pT));
}
public static bool operator !=(ReadOnly<T> pReadOnlyT, T pT)
{
return !(pReadOnlyT == pT);
}
}
Exemplo de uso:
var rInt = new ReadOnly<int>(5);
if (rInt == 5)
{
//Int is 5 indeed
}
var copyValueOfInt = rInt.Value;
//rInt.Value = 6; //Doesn't compile, setter is private
Talvez não menos código, rvar rInt = 5
mas funciona.
Você pode declarar variáveis locais somente leitura em C #, se estiver usando o compilador interativo C # csi
:
>"C:\Program Files (x86)\MSBuild\14.0\Bin\csi.exe"
Microsoft (R) Visual C# Interactive Compiler version 1.3.1.60616
Copyright (C) Microsoft Corporation. All rights reserved.
Type "#help" for more information.
> readonly var message = "hello";
> message = "goodbye";
(1,1): error CS0191: A readonly field cannot be assigned to (except in a constructor or a variable initializer)
Você também pode declarar variáveis locais somente leitura no .csx
formato de script.
message
não é uma variável aqui, ela é compilada em um campo. Isso não é picuinhas porque a distinção existe claramente no C # interativo também: int x; Console.WriteLine(x)
é C # interativo legal (porque x
é um campo e inicializado implicitamente), mas void foo() { int x; Console.WriteLine(x); }
não é (porque x
é uma variável e usada antes de ser atribuída). Além disso, Expression<Func<int>> y = x; ((MemberExpression) y.Body).Member.MemberType
revelará que x
é realmente um campo e não uma variável local.
c # já tem um var somente leitura, embora em uma sintaxe um pouco diferente:
Considere as seguintes linhas:
var mutable = myImmutableCalculationMethod();
readonly var immutable = mutable; // not allowed in C# 8 and prior versions
return immutable;
Compare com:
var mutable = myImmutableCalculationMethod();
string immutable() => mutable; // allowed in C# 7
return immutable();
É certo que a primeira solução poderia ser menos código para escrever. Mas o segundo fragmento tornará o somente leitura explícito, ao fazer referência à variável.
readonly var im = new List<string>(); im.Add("read-only variable, mutable object!");
.
usar const
palavra-chave para tornar a variável somente leitura.
referência: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const
public class SealedTest
{
static void Main()
{
const int c = 707;
Console.WriteLine("My local constant = {0}", c);
}
}
const
onde a variável só pode ser atribuída durante sua inicialização - não no estilo csharp, const
onde apenas expressões de tempo de compilação podem ser usadas. Por exemplo, você não pode fazer, const object c = new object();
mas um readonly
local permitiria que você fizesse isso.