代码之家  ›  专栏  ›  技术社区  ›  Vladislav Hromyh

为什么集合初始值设定项只使用getter属性?

  •  5
  • Vladislav Hromyh  · 技术社区  · 8 年前

    这对我来说是非常不可预知的代码结果。

    我没想到这段代码会产生这样的结果。

    所以,我读了Jeffrey Richter的书(clr ia c#),其中有一个代码示例。

    internal class ClassRoom
    {
        private List<String> _students = new List<string>();
        public List<String> Students { get { return _students; } }
    }
    
    ClassRoom classRoom = new ClassRoom
    {
        Students = {"Mike", "Johny", "Vlad", "Stas"}
    };
    
    foreach (var some in classRoom.Students)
    {
        Console.WriteLine(some);
    }
    

    而且,正如你们中的一些人所建议的,我们可以在控制台中看到四个名称。 所以,我的问题是:

    如果我们的名字会出现在Students和_Students中,但由于没有Students-setter,这些名字没有被分配,那么我们如何得到我们的名字呢。

    __________编辑_1_______________

    我读了你的答案,谢谢你。

    但是,你知道,这是一种误解。。。 我真的搞不懂。

    当我初始化时 学生 ,我初始化 _学生 ?

    同样重要的是,当我从IEnumerable中获取变量时( 一些 ), 我从中获取变量 学生 ? 我想没有。

    我不明白,我到底在哪里分配变量(INITALIZE) _学生 收藏?

    谢谢你帮我弄明白!

    3 回复  |  直到 8 年前
        1
  •  1
  •   Eric Lippert    8 年前

    这些其他答案是 几乎 正当让我们仔细检查一下,然后真正把它做好。

    为什么集合初始值设定项只使用getter属性?

    因为属性值没有更改。属性引用的集合的内容已更改。

    把一个属性看作一个桶。您不能更改属性引用的bucket,但可以更改bucket的内容。

    如果我们的名字会出现在Students和_Students中,但由于没有Students-setter,这些名字没有被分配,那么我们如何得到我们的名字呢。

    学生属性根本没有分配。怎么可能?它没有setter。

    这些名称被添加到Students getter引用的集合中。

    初始化学生时,初始化_学生?

    否。_students的初始化是为_studens赋值的行。

    集合初始值设定项 将值添加到现有集合 。变量_students已初始化。

    当我从IEnumerable(some)中获取变量时,我从学生那里获取变量?

    你不需要 变量 从任何地方。你拿着 价值观 变量不是值;变量 包含 价值观不要将存储与存储的值混淆。

    我不明白,我到底在哪里分配变量(INITALIZE)_students集合?

    _students变量在初始化_studens的行中初始化。这个 目录 在包含内容的行中初始化集合的。

    也许它将有助于准确列出发生的一切:

    • 创建新的Classroom对象;_students字段为空;将生成对该对象的引用。
    • 创建一个新的空列表;对列表的引用被复制到新创建的Classroom对象的_students字段中。
    • 对新Classroom对象的引用调用Students getter。它返回_students的内容,这是对空列表的引用。
    • 该列表中添加了四项
    • 对Classroom对象的引用被复制到Classroom变量。

    或者,在代码中,这相当于:

    c = create a Classroom
    c._students = null
    l1 = create a List<string>
    c._students = l1
    l2 = c.Students -- which returns c._students
    l2.Add("...")  -- four times
    classRoom = c
    

    你看,从来没有一个叫“二传手”的学生。没有必要。它所做的只是获取_students中包含的引用,该引用已经由字段初始值设定项初始化。

        2
  •  1
  •   Rahul    8 年前

    通过说 Students = {"Mike", "Johny", "Vlad", "Stas"} 它在做什么

    所有物 Students 返回基础 List<String> _students 实例,然后使用集合初始值设定项添加字符串文本。

    因此,当我迭代学生时,我是否迭代了 _学生?

    技术上是的,您的 _students 是一个 private 变量和 学生 属性是该私有字段的包装,以将该列表的访问权授予外部使用者。

    所以当你说 Students = ... 实际上,您正在设置或初始化私有字段,因为访问 学生 会还给你 List<string> 例子

        3
  •  1
  •   blins    8 年前

    这个 _students 字段在构造时在内部分配一次,由于缺少公共setter,因此无法从外部将其设置为不同的列表实例。ClassRoom的对象初始值设定项实际上没有设置 Students collection属性,但它只是利用集合初始值设定项语法 添加 初始项目 学生 ...

    ClassRoom classRoom = new ClassRoom
    {
        Students = { "Mike", "Johny", "Vlad", "Stas" }
    };
    

    由于对象初始值设定项版本不执行对 classRoom 直到填充集合之后。

    ClassRoom classRoom = new ClassRoom();
    classRoom.Students.Add("Mike");
    classRoom.Students.Add("Johny");
    classRoom.Students.Add("Vlad");
    classRoom.Students.Add("Stas");
    

    相反,请注意,由于缺少公共setter,以下内容将产生编译器错误,因此访问确实受到了预期的限制。。。

    ClassRoom classRoom = new ClassRoom
    {
        Students = new List<string> { "Mike", "Johny", "Vlad", "Stas" }
    }