10

Jeffrey Richter の本 (C# 4.0 による CLR、257 ページ) で奇妙なコードを見つけたばかりで、なぜそのように機能するのかを誤解しています。

    public sealed class Classroom
    {
        private List<String> m_students = new List<String>();
        public List<String> Students { get { return m_students; } }

        public Classroom() { }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Classroom classroom = new Classroom {
                Students = { "Jeff", "Kristin" }
            };

            foreach (var student in classroom.Students)
                Console.WriteLine(student);
        }
    }

結果:

Jeff
Kristin

ご覧のとおり、「Students」という名前のアクセサ プロパティがあります。これには getter しかありません (setter ではありません!)が、「Main」関数では、「classroom」変数を初期化したい場合に「Students」フィールドを初期化します。 「教室」タイプの:

Classroom classroom = new Classroom {
    Students = { "Jeff", "Kristin" }
};

私はいつも、変数が式の「左側」(int i = 1) にある場合、コンパイラはセッター関数にアクセスし、「右側」(int x = i + 2) にある場合はゲッター関数にアクセスする必要があると考えていました。 .

Jeffrey のコードでは、なぜこのように興味深い動作が行われるのでしょうか (それは私のためだけなのかもしれません。そうである場合は申し訳ありません)。

4

1 に答える 1

24

C# 5 仕様のセクション 7.6.10.2 から:

等号の後にコレクション初期化子を指定するメンバー初期化子は、埋め込みコレクションの初期化です。フィールドまたはプロパティに新しいコレクションを割り当てる代わりに、初期化子で指定された要素が、フィールドまたはプロパティによって参照されるコレクションに追加されます。フィールドまたはプロパティは、§7.6.10.3 で指定された要件を満たすコレクション型である必要があります。

したがって、このコード:

Classroom classroom = new Classroom {
    Students = { "Jeff", "Kristin" }
};

次と同等です。

Classroom tmp = new Classroom();
tmp.Students.Add("Jeff");
tmp.Students.Add("Kristin");
Classroom classroom = tmp;

基本的に=、オブジェクト初期化子内は、スタンドアロンの割り当てステートメントとまったく同じではありません。

編集:このコード

Classroom classroom = new Classroom {
    Students = new List<string> { "Jeff", "Kristin" }
};

のセッターを呼び出そうとするため、コンパイルに失敗しますStudent

于 2013-06-26T13:52:33.370 に答える