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