首先,我会说我已经改变了我的设计,不再需要它,但得到一个好的答案仍然会很好
我的代码中有以下class
,ListContainer
(附加的代码全部是mcve):
class ListContainer
{
public object ContainedList
{
get; private set;
}
public int Value
{
get; private set;
}
public ListContainer(object list, int value)
{
ContainedList = list;
Value = value;
}
}
在我的代码中的其他class
我有一个List<ListContainer>
我需要每个ListContainer
来包含这个List<ListContainer>
,所以我可以像这样实现它:< / p>
//Field in the class
List<ListContainer> mContainers = null;
//In the constructor:
mContainers = new List<ListContainer>();
mContainers.Add(new ListContainer(mContainers, SOME_CONST));
mContainers.Add(new ListContainer(mContainers, SOME_OTHER_CONST));
比它工作正常,但当我尝试使用 列表初始值设定项 时:
//Field in the class
List<ListContainer> mContainers = null;
//In the constructor:
mContainers = new List<ListContainer>
{
new ListContainer(mContainers, SOME_CONST),
new ListContainer(mContainers, SOME_OTHER_CONST)
}
你会期望结果是等价的,但实际上结果看起来像是:
mContainers
[0] - ListContainer
ContainedList = null
Value = SOME_CONST
[1] - ListContainer
ContainedList = null
Value = SOME_OTHER_CONST
看到这个结果我已经检查了这个C#编译的输出MSIL并看到了以下代码:
现在,这解释了问题出现的原因,我甚至在 CSharp语言规范 文档中检出了这是定义的行为:
可以按如下方式创建和初始化列表:
var contacts = new List<Contact> { new Contact { Name = "Chris Smith", PhoneNumbers = { "206-555-0101", "425-882-8080" } }, new Contact { Name = "Bob Harris", PhoneNumbers = { "650-555-0199" } } };
与
具有相同的效果var __clist = new List<Contact>(); Contact __c1 = new Contact(); __c1.Name = "Chris Smith"; __c1.PhoneNumbers.Add("206-555-0101"); __c1.PhoneNumbers.Add("425-882-8080"); __clist.Add(__c1); Contact __c2 = new Contact(); __c2.Name = "Bob Harris"; __c2.PhoneNumbers.Add("650-555-0199"); __clist.Add(__c2); var contacts = __clist;
其中__clist,__ c1和__c2是临时变量,否则这些变量将不可见且无法访问。
显然,这种行为是有意的。是否有充分的理由在临时变量上完成所有操作,而不是在原始变量上完成?因为这对我来说似乎是一种错误的行为。
答案 0 :(得分:4)
原因是避免竞争条件,并发线程访问原始变量,您将添加元素。如果线程访问变量而未添加所有元素,则会出现不一致。
访问同一变量的两个线程因此会得到一个不一致的列表,其中包含不同的元素。
如果将元素添加到不同的行上,这不会令人震惊,但由于您使用了对象初始化程序,因此将对象视为直接初始化其所有元素是正常的,因此需要临时,隐形,变量。
答案 1 :(得分:2)
是否有充分的理由在临时列表上完成所有操作而不是原始列表?
没有原始列表:
var __clist = new List<Contact>();
// …
__clist.Add(__c1);
// …
__clist.Add(__c2);
var contacts = __clist;
只创建了一个列表。您可能意味着它是在临时变量而不是原始变量上完成的,但这没有实际效果 - 除了可能更容易实现。如果您认为集合初始化不仅限于变量赋值的上下文,则尤其如此:
SomeMethodCall(new List<int>() { 1, 2, 3 });
由于没有对该列表的引用,实现它的最简单的解决方案就是使用一个保存列表的临时变量,然后将该变量放在初始化器的位置。
对此重要的是旧值被完全覆盖。因此,在mContainers = new List<ListContainer>
中,mContainers
的旧值永远不会被用于初始化语法的目的。
将集合初始化视为“原子”操作可能是个好主意。整个初始化程序完成后,该列表仅存在(至少对您而言)。因此,您无法在初始化程序中引用自身。
答案 2 :(得分:1)
首先在=
的右侧评估作业,然后进行作业。所以mContainers
仍为空。