10

我刚刚发现 Jeffrey Richter 书中的代码(CLR via C# 4.0,第 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)的'left-side'中的变量时,编译器应该访问setter函数,而在'right-side'(int x = i + 2)中访问getter函数.

为什么在 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 回答