これについて同僚と友好的な議論をする。私たちはこれについていくつかの考えを持っていますが、SO群衆はこれについてどう考えていますか?
1つの理由は、読み取り専用ローカルのCLRサポートがないことです。読み取り専用は、CLR/CLI initonlyオペコードに変換されます。このフラグはフィールドにのみ適用でき、ローカルでは意味がありません。実際、それをローカルに適用すると、検証不可能なコードが生成される可能性があります。
これは、C#がこれを実行できなかったという意味ではありません。ただし、同じ言語構成に対して2つの異なる意味を与えます。ローカルのバージョンには、CLRに相当するマッピングがありません。
C#アーキテクトの一部に対する判断は下手だと思います。ローカル変数のreadonly修飾子は、プログラムの正確性を維持するのに役立ち(アサートと同様)、コンパイラがコードを最適化するのに役立つ可能性があります(少なくとも他の言語の場合)。現在C#で許可されていないという事実は、C#の「機能」の一部がその作成者の個人的なコーディングスタイルの単なる施行であるという別の主張です。
Jaredの答えに答えると、おそらくコンパイル時の機能である必要があります-コンパイラーは、初期宣言の後の変数への書き込みを禁止します(割り当てを含める必要があります)。
これに価値がありますか?可能性-しかし、多くはないが、正直に言うと。変数がメソッドの他の場所に割り当てられるかどうかを簡単に判断できない場合、メソッドが長すぎます。
価値のあるものとして、Javaにはこの機能があり(final
修飾子を使用)、私はveryを使用することはめったにありません。 it hasを使用して、変数を匿名の内部クラスでキャプチャできるようにします。-isを使用すると、有用な情報ではなく、混乱した印象を与えます。
提案 readonly locals and parameters は、C#7設計チームによって簡単に議論されました。 2015年1月21日のC#デザインミーティングノート :
パラメーターとローカルはラムダによってキャプチャーされ、それにより同時にアクセスできますが、共有相互状態の問題からそれらを保護する方法はありません。それらは読み取り専用にはできません。
一般に、ほとんどのパラメーターと多くのローカルは、初期値を取得した後に割り当てられることを意図していません。それらに対して読み取り専用を許可すると、その意図が明確に表現されます。
1つの問題は、この機能が「魅力的な迷惑」になる可能性があることです。行うべき「正しいこと」はほとんどの場合、パラメーターとローカルを読み取り専用にすることですが、そうすることはコードを大幅に混乱させます。
これを部分的に軽減するアイデアは、ローカル変数のreadonly varの組み合わせをvalまたはそのような短いものに縮小できるようにすることです。より一般的には、読み取り専用を表すために、確立された読み取り専用よりも短いキーワードを考えてみることができます。
C#Language Designリポジトリで議論が続けられています。あなたの支持を示すために投票してください。 https://github.com/dotnet/csharplang/issues/188
これは、c#言語デザイナーにとっては見落としです。 F#にはvalキーワードがあり、CLRに基づいています。 C#で同じ言語機能を使用できない理由はありません。
私はその同僚であり、フレンドリーではありませんでした! (冗談だ)
短いメソッドを記述する方が良いため、この機能を削除しません。スレッドは難しいので使用しないでくださいと言っているようなものです。ナイフを渡して、自分を切らないように責任を負わせてください。
個人的には、「inv」(不変)や「rvar」のような別の「var」タイプのキーワードが乱雑を避けたいと思っていました。私は最近F#を研究してきましたが、不変なものが魅力的だと感じました。
決して知らなかったJavaこれがあった。
ローカルconst変数が好きなのと同じ方法で、ローカルreadonly変数が欲しいです。ただし、他のトピックよりも優先度は低くなります。
たぶん優先度は、C#デザイナーがこの機能を実装しない(まだ!)と同じ理由です。ただし、将来のバージョンでローカルの読み取り専用変数をサポートするのは簡単です(そして下位互換性がある)。
読み取り専用は、インスタンス変数を設定できる唯一の場所がコンストラクター内にあることを意味します。変数をローカルに宣言する場合、インスタンスは存在せず(スコープ内にのみあります)、コンストラクターは変更できません。
私は知っている、これはあなたの質問の理由に答えていない。とにかく、この質問を読んでいる人は以下のコードを高く評価するかもしれません。
一度だけ設定する必要があるローカル変数をオーバーライドするときに自分の足を撃つことに本当に関心があり、それをよりグローバルにアクセス可能な変数にしたくない場合は、このようなことをすることができます。
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);
}
}
使用例:
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
おそらく、rvar rInt = 5
しかし、それは動作します。
c#には、多少異なる構文ではありますが、すでに読み取り専用変数があります。
次の行を考慮してください。
var mutable = myImmutableCalculationMethod();
readonly var immutable = mutable; // not allowed in C# 8 and prior versions
return immutable;
と比べて:
var mutable = myImmutableCalculationMethod();
string immutable() => mutable; // allowed in C# 7
return immutable();
確かに、最初の解決策は、記述するコードが少なくなる可能性があります。しかし、2番目のスニペットは、変数を参照するときに読み取り専用を明示的にします。
C#インタラクティブコンパイラcsi
を使用している場合、C#で読み取り専用ローカル変数を宣言できます。
>"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)
.csx
スクリプト形式で読み取り専用ローカル変数を宣言することもできます。