C#のメーリングリストに出た質問("[CS:07442] 構造体について")について考えているうちに、バグらしきものを1つ発見したのでメモっておきます。
概要 §
環境は、Visual Studio.NET 2003です。
C#において、privateなフィールドに構造体を記述した時、それに明示的な初期化構文(newを使う)や、値を代入するコードが存在しない場合に、以下の警告が出ます。
コンパイラの警告 (レベル 4) CS0649
フィールド 'field' は割り当てられません。常に既定値 'value' を使用します。
回避方法 §
明示的な初期化構文を入れる。(例: private 構造体名 = new 構造体名() )
Visual Studio 2005へアップグレードする。(Visual C# Express 2005 Beta2では発生しませんでした)
警告の詳細 §
警告の詳細(日本語版)
警告の詳細(英語版)
サンプルソース §
検証のためのサンプルソースを以下に示します。
using System;
namespace ConsoleApplication55
{
struct SampleStruct
{
}
class SampleClass
{
}
class Class1
{
private SampleStruct sampleStruct; // ※1
private SampleClass sampleClass; // ※2
[STAThread]
static void Main(string[] args)
{
Class1 t1 = new Class1();
t1.sampleStruct.ToString();
t1.sampleClass.ToString(); // ※3
}
}
}
解説 §
Visual Studio.NET 2003でビルドを行うと、※1と※2の両方で上記の警告が発生します。
※2の行でこの警告が発生することは有益です。なぜなら、このプログラムを実行すると、確実に※3の行でnullポインタ参照の例外が起きるからです。その可能性を、コンパイル時点で指摘してくれています。
しかし、※1の行で警告が出ることは無意味です。なぜなら、明示的な初期化構文のない構造体宣言であっても、初期化は行われるからです。つまり、明示的な初期化構文の不在は、実行に際して特に致命的な問題を引き起こしません。
C# 言語の仕様 11.3.4 既定値より引用
「5.2 既定値」で説明しているように、複数種類の変数は、その作成時に既定値に自動的に初期化されます。クラス型およびその他の参照型の変数の場合、この既定値は null です。構造体は null に設定できない値型なので、構造体の既定値は、すべての値型フィールドをその既定値に、およびすべての参照型フィールドを null に設定することで生成される値です。
もし、これがバグとして認識される挙動であるならば、既にVisual Studio 2005で修正済みである可能性があると考え、Visual C# Express 2005 Beta2で検証したところ、※2の行で発生する有益な警告は得られたものの、※1の行で発生していた無意味な警告は出なくなっていました。
そのようなわけで、とりあえずバグであろう、と判断しました。
感想 §
調べていて、久々に面白かったというのが正直なところです。
特に、一時的に自分がC#の文法を理解して「いない」ような気持ちに陥ったことがエキサイティングで面白かったですねぇ。
やはりC#は面白いな、とも思いました。
ちなみに、C#のメーリングリストに出た質問に含まれるコードの一部に、全角空白が入っていて、それに気付かないで焦りまくったのも面白い出来事です。実は変なところに全角空白が入っていても、コンパイルエラーにならず、しかも半角空白と同じに扱われるわけでもない事例がありました。