これは、プログラミング プロセス中にチーム メンバーの 1 人が提起した質問です。このコンパイル エラーは簡単に回避できるため、私は彼のコードを見てこの問題がそれほど単純ではないことに気づくまで、この問題について注意深く考えたことはありませんでした。
まずこのコードを見てください。
コード
クラスプログラム
{
static void Main(string[] args)
{
byte[] buf = 新しいバイト[1024];
T t = 新しい T();
文字列 str = "1234";
int n = 1234;
int?nn = 1234;
DateTime dt = DateTime.Now;
オブジェクト o = 1234;
Console.WriteLine("終了");
}
}
クラス T { }
このコード内で未使用の変数がいくつあると思いますか?
プログラマの観点から見ると、答えはすべての変数が未使用であるということになります。しかし、コンパイラによって与えられる結果は少し直観に反しています。
変数「str」には値が割り当てられていますが、その値は一度も使用されていません。変数「n」には値が割り当てられていますが、その値は一度も使用されていません。値は一度も使用されていません。
奇妙なのは、すべての変数が同じ方法で宣言されているにもかかわらず、コンパイラーはそれらの一部が未使用であるとのみ認識することです。どうしたの?
それらを一つずつ分析してみましょう。まず配列を確認します。デフォルト値が使用されている場合、コンパイラによって与えられる情報は異なります。
byte[] buf1 = null // 警告があります。
byte[] buf2 = new byte[1024]; // 警告なし
この結果は、パラメーターの割り当てが null の場合、コンパイラーは実際には割り当てを実行せず、変数が使用されていないかのように扱われることを示しているようです。 IL 検査の結果も、このステートメントを証明できます。最初の行では、コンパイラーは対応するステートメントを生成しませんでしたが、2 行目では、配列の作成に newattr 命令が使用されました。
カスタムクラスの場合:
T t1 = null // 警告があります。
T t2 = new T() // 警告なし
この結果は理解できるはずです (理解できますが、以下に示す理由から、それが良いとは思いません)。クラスのメソッドを呼び出していませんが、クラスのコンストラクターは依然としていくつかの操作を実行する可能性があるため、クラスが作成されている限り、コンパイラーはそのクラスを使用済みであるかのように扱います。
基本的な値型の場合、その動作は参照型とは異なります。コンパイラーは初期代入を変数の使用として扱いません。
int n1 = 0; // 警告があります。
int n2 = 1234; // 警告があります。
int? n3 = null;
int? n4 = 0;
int? n5 = 1234;
String は実装上は参照型とみなされますが、パフォーマンスは値型に近く、警告情報も値型と同じです。
もう少し複雑な値の型の場合、結果はもう少し微妙になります。
DateTime dt1 // 警告があります。
DateTime dt2 = new DateTime(); // 警告があります。
DateTime dt3 = new DateTime(2009,1,1); // 警告なし
DateTime dt4 = DateTime.Now // 警告なし;
この結果について注意すべき点が 1 つあります。 DateTime のデフォルト コンストラクターとパラメーター化されたコンストラクターはどちらもユーザーの観点からはコンストラクターですが、コンパイラーの観点からは異なります。また、IL で逆コンパイルすると、デフォルトのコンストラクターが呼び出された場合、コンパイラーは initobj 命令を呼び出しますが、パラメーター化されたコンストラクターには call ctor 命令が使用されることがわかります。さらに、プログラマの観点からは割り当てコードの形式はまったく同じですが、コンパイラは割り当てられた値に応じて異なる構築戦略を採用しますが、これも直感に反します。
最終的な結論は残念です。つまり、C# のコンパイル警告は、特に配列に対してプログラマに十分な保護を与えるには十分ではありません。
byte[] buf = 新しいバイト[1024];
このような配列を使用せずに構築するだけの場合、コンパイラはプログラマに警告メッセージを表示しません。
考慮する価値のあるもう 1 つの問題は、メソッドを使用せずにクラスを宣言することです。
T t = 新しい T()
これは合理的な行動ですか?コンパイラはこれに対して警告を発行する必要がありますか?
私の個人的な意見は、使用法という観点から見ると、これは不合理であり、コンパイラはこの使用法を発見した場合に警告を発するべきである、というものです。必要に応じて、コンパイル ディレクティブまたは Attribute メソッドを通じて警告メッセージを明示的に宣言することで、警告メッセージを回避できます。ただし、C# コンパイラの動作は警告を発行しないので、これには同意できません。もちろん、皆さんもそれぞれのアイデアを出していただければと思います。