2

我有一个具有集合属性的类:

class MyClass
{
    public MyCollection Coll { get; private set; }
    public MyClass() { this.Coll = new MyCollection(); }
}

class MyCollection : IList { ... }

现在我正在创建我的类的两个不同实例:

var o1 = new MyClass() { Coll = {"1", "2"}};
var o2 = new MyClass() { Coll = new MyCollection() {"1", "2"} };

我知道编译器抱怨后者,因为该属性的设置器不存在(或者在这种情况下不可公开访问)。然而,第一个也是一个赋值 - 尽管是一个集合初始化器。

我假设集合初始化器被允许用于仅获取属性,因为它们只是调用Add而不IList实际调用属性的获取器。这是正确的吗?

4

1 回答 1

2

从你的问题:

我假设集合初始值设定项 [...] 只是调用Add[ IList...]。

这个假设是正确的。集合初始值设定项是 C# 编译器在编译期间转换为更明确的语法糖。例如,以下行:

var l = new List<int>() { 1, 2 };

实际翻译为:

var l = new List<int>();
l.Add(1);
l.Add(2);

您可以通过查看生成的 MSIL(稍微简化)来验证这一点:

newobj      List<System.Int32>..ctor // Create list object.
stloc.0                              // Store list object as local variable "0".
ldloc.0                              // Push local variable "0" onto the stack.
ldc.i4.1                             // Push 4-byte integer constant "1" onto the stack.
callvirt    List<System.Int32>.Add   // Call "Add" (uses and pops the last two values from
                                     // the stack).
ldloc.0                              // Push list onto stack again.
ldc.i4.2                             // Push constant "2" onto stack.
callvirt    List<System.Int32>.Add   // Call "Add" again.

这意味着您的代码var o1 = new MyClass() { Coll = {"1", "2"}};永远不会访问私有设置器。它只是像这样获取Coll并调用Add它:

var o1 = new MyClass();
o1.Coll.Add("1");
o1.Coll.Add("2");

我们可以再次检查 MSIL 来验证这一点:

newobj      MyClass..ctor
stloc.1                              // Store MyClass instance at local variable "1".
ldloc.1                              // Load MyClass instance onto stack.
callvirt    MyClass.get_Coll         // Call getter of "Coll" and push the MyCollection
                                     // instance onto the stack.
ldstr       "1"                      // Push the string "1" onto the stack...
callvirt    MyCollection.Add         // ...and call "Add".
pop                                  // Discard the return value of "Add".
ldloc.1
callvirt    MyClass.get_Coll
ldstr       "2"
callvirt    MyCollection.Add
pop
于 2016-08-05T15:03:07.157 回答