在 class 上初始化集合成员
initialize collection-member on a class
我有一个 class 有一个集合-属性:
class MyClass
{
public MyCollection Coll { get; private set; }
public MyClass() { this.Coll = new MyCollection(); }
}
class MyCollection : IList { ... }
现在我正在为 class 创建两个不同的实例:
var o1 = new MyClass() { Coll = {"1", "2"}};
var o2 = new MyClass() { Coll = new MyCollection() {"1", "2"} };
我知道编译器抱怨后者,因为 属性 的 setter 不存在(或者在这种情况下不可公开访问)。然而,第一个也是一个赋值——尽管是一个集合初始化器。
我假设集合初始化器允许用于只获取属性,因为它们只是在 IList
上调用 Add
而实际上并不调用 getter 的 属性。这样对吗?
根据你的问题:
I assume that collection initializers are [...] just calling Add
on 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"}};
永远不会访问私有 setter。它只是获取 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
我有一个 class 有一个集合-属性:
class MyClass
{
public MyCollection Coll { get; private set; }
public MyClass() { this.Coll = new MyCollection(); }
}
class MyCollection : IList { ... }
现在我正在为 class 创建两个不同的实例:
var o1 = new MyClass() { Coll = {"1", "2"}};
var o2 = new MyClass() { Coll = new MyCollection() {"1", "2"} };
我知道编译器抱怨后者,因为 属性 的 setter 不存在(或者在这种情况下不可公开访问)。然而,第一个也是一个赋值——尽管是一个集合初始化器。
我假设集合初始化器允许用于只获取属性,因为它们只是在 IList
上调用 Add
而实际上并不调用 getter 的 属性。这样对吗?
根据你的问题:
I assume that collection initializers are [...] just calling
Add
onIList
[...].
这个假设是正确的。集合初始值设定项是语法糖,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"}};
永远不会访问私有 setter。它只是获取 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