【问题标题】:Weird syntax of collection initializers集合初始化器的奇怪语法
【发布时间】:2015-12-22 08:02:25
【问题描述】:

假设,我们有一个非常简单的类:

class ObjectList {
    public List<string> List1 { get; } = new List<string>();
    public List<string> List2 { get; set; }
}

我们想要创建这个类的一个实例:

ObjectList objectList = new ObjectList {
    List1 = { "asdf", "qwer" },
    List2 = new List<string> { "zxcv", "1234" }
};

所以,在 List2 的情况下是可以的,使用“=”我们设置属性。但是在 List1 的情况下,看起来我们设置了属性,但实际上,我们假设在之前的某个地方设置了它,这里我们只设置了值。和数组初始化非常相似:

string[] arr = { "val1", "val2" }

为什么 C# 在这里使用这种令人困惑的语法?

编辑: 我想我用 C# 6.0 语法把很多观众弄糊涂了,但这不是重点。让我们使用旧的好 C# 3.0 和 .net 2.0。正如 Jeff Mercado 建议的那样,让我们​​也添加更多乐趣,并从一开始就将一些值(“1”和“2”)添加到列表中:

class Program {
    static void Main(string[] args) {
        ObjectList objectList = new ObjectList {
            List1 = { "asdf", "qwer" },
        };
    }
}
class ObjectList {
    List<string> _List1 = new List<string>() { "1", "2" };
    public List<string> List1 {
        get {
            return _List1;
        }
    }
}

它显示了同样奇怪的语法。最后我有 list { "1", "2", "asdf", "qwer" },这更令人困惑。我可以期待这个。

【问题讨论】:

  • 编译? List1 没有公共设置器,因此您应该无法在初始化程序语法中设置它。
  • 确实如此。编译器实际上将该语法转换为对 .Add() 的调用
  • 我同意,这种语法真的很奇怪。从语义上讲,它更像+=。对于嵌套对象初始化器来说,这完全一样——没有构造函数调用,初始化器只会设置属性。
  • 显然,在初始化程序的上下文中,您只是使用集合初始化程序语法,并且您只是向List1 实例添加更多项。您可以验证是否实际保留了初始列表实例。尝试使用非空列表进行初始化或检查引用,您会发现它没有改变。
  • @HenkHolterman 没有解释为什么选择该特定语法。 OP 已经意识到这种行为

标签: c#


【解决方案1】:

为什么 C# 在这里使用这种令人困惑的语法?

你说得对,这有点奇怪,但那是因为你混合了 2 个原则。正如几个 cmets 已经指出的那样,{ item1, items2 } 语法转换为 .Add(itemN) 调用 = 左侧的项目是一个集合时

所以奇怪是因为

List<SomeClass> list = new List<SomeClass> { item1, item2 };
SomeClass[] array = { item1, item2 };

区别对待。

另一部分是您的样本移动了new List&lt;SomeClass&gt;,但在两种情况下都存在。

【讨论】:

  • 我宁愿说奇怪是赋值运算符 (=) 没有做任何赋值的结果。
  • 我还没有全貌。 C#,在所有语言中。看起来很整洁,但是做 .add() 的赋值看起来像是语言中的一个错误。 C# 团队必须有一个非常严肃的原因才能添加这个,我想知道。
【解决方案2】:

答案已经由Eric Lipperthis answer to Why is an Add method required for { } initialization?中给出

集合初始化器的典型使用场景激发的设计目标是使现有集合类型的初始化可以在表达式语法中进行,以便集合初始化器可以嵌入到查询理解中或转换为表达式树。

其他场景的优先级较低; 该功能之所以存在,是因为它有助于 LINQ 工作

看来,即使这种语法在创建只读集合时更有意义,它还是被添加了,以便他们可以按时交付 LINQ。

【讨论】:

  • 嗯.. 有趣的故事。但它对 LINQ 有何帮助?
  • 它在引用中说得对:“使现有集合类型的初始化在表达式语法中成为可能”
  • 你能举个例子吗?我想我从来没有那样用过它,所以我很难想象它。
  • @AlexButenko 考虑这段代码:var q = from x in someCollection select new ObjectList { List1 = { "qwerty", "asdfgh" } } 其中someCollectionIEnumerable&lt;T&gt; 如果不使用let 或包含在{ ... } 中的多个语句,就不可能在一个表达式中声明它跨度>
  • @AlexButenko:因为您希望能够区分“我正在添加到现有列表”和“我想要使用这些项目创建新列表”这两种情况。我同意这是一个微妙且有些令人困惑的区别,但语言需要有一种方式来表达这两个概念。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-22
  • 1970-01-01
  • 1970-01-01
  • 2017-05-18
相关资源
最近更新 更多