该列表初始值设定项行为是否应在Visual Studio C#编译器中报告为错误?

该列表初始值设定项行为是否应在Visual Studio C#编译器中报告为错误?,c#,.net,list,compilation,initialization,C#,.net,List,Compilation,Initialization,首先,我要说的是,我已经改变了我的设计,不再需要它,但得到一个好的答案仍然很好 我的代码中有以下类,列表容器(所附代码均为): 在另一个类中,我的代码中有一个列表,我需要每个列表容器包含这个列表,所以我可以这样实现它: //Field in the class List<ListContainer> mContainers = null; //In the constructor: mContainers = new List<ListContainer>(); mCo

首先,我要说的是,我已经改变了我的设计,不再需要它,但得到一个好的答案仍然很好

我的代码中有以下
列表容器
(所附代码均为):

在另一个
中,我的代码中有一个
列表
,我需要每个
列表容器
包含这个
列表
,所以我可以这样实现它:

//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));
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 contacts=新列表{
新联系人{
Name=“克里斯·史密斯”,
电话号码={“206-555-0101”,“425-882-8080”}
},
新联系人{
Name=“Bob Harris”,
电话号码={“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;
var\uuu clist=new List();
触点_c1=新触点();
__c1.Name=“克里斯·史密斯”;
__c1.电话号码。添加(“206-555-0101”);
__c1.电话号码。添加(“425-882-8080”);
__clist.Add(uu c1);
触点_c2=新触点();
__c2.Name=“鲍勃·哈里斯”;
__c2.电话号码。添加(“650-555-0199”);
__clist.Add(uu c2);
var触点=_clist;
其中_clist、_c1和_c2是临时变量,在其他情况下不可见且不可访问


显然,这种行为是有意的。是否有充分的理由说明所有操作都是在临时变量而不是原始变量上进行的?因为对我来说这似乎是一种错误的行为。

作业首先在
=
的右侧进行评估,然后进行作业。因此,
mContainers
仍然为空。

原因是为了避免并发线程访问您要添加元素的原始变量时出现争用情况。如果线程访问变量时尚未将所有元素添加到变量中,则会出现不一致

因此,访问同一变量的两个线程将得到一个不一致的列表,其中包含不同的元素

如果元素添加到不同的行上,这不会让人感到震惊,但由于使用了对象初始值设定项,因此通常会将对象视为使用其所有元素直接初始化,因此需要一个临时的、不可见的变量

是否有充分的理由将所有事情都放在临时清单上而不是原来的清单上

没有原始列表:

var __clist = new List<Contact>();
// …
__clist.Add(__c1);
// …
__clist.Add(__c2);
var contacts = __clist;
var\uuu clist=new List();
// …
__clist.Add(uu c1);
// …
__clist.Add(uu c2);
var触点=_clist;
只创建了一个列表。您可能的意思是,它是在一个临时变量上完成的,而不是在原始变量上完成的,但是除了更容易实现之外,这没有任何实际效果。如果您认为集合初始化不限于变量赋值的上下文,则尤其如此:

SomeMethodCall(new List<int>() { 1, 2, 3 });
SomeMethodCall(新列表(){1,2,3});
由于没有对该列表的引用,实现该列表的最简单解决方案就是使用一个保存该列表的临时变量,然后将该变量放在初始值设定项的位置

同样重要的是,旧值被完全覆盖。因此,在您的
mContainers=new列表中,
mContainers
的旧值在初始化器语法中永远不会被查看


将集合初始化视为“原子”操作可能是个好主意。该列表仅在整个初始值设定项完成后才存在(至少对您而言)。所以你不能从初始值设定项中引用自己。

重读我的问题,我明白发生了什么,我只是不明白did行为有什么好处。它仍然让我恼火的是,列表初始值设定项仅作为正常初始化和添加的甜美语法存在,所以它的行为应该是一样的……好吧,是和否。这是语法上的甜点,是的,但从哲学上讲,这是一个不同的概念:ObjectInitializer:你的对象是用那些已经设置好的值初始化的。如果可以在初始化完成之前访问对象,则不能将其称为对象初始值设定项这不是竞争条件保护。ECMA允许JIT完全撤销此转换。如果这是你唯一的种族保护,你就没有了。我对你的评论很感兴趣,@usr:你能详细说明一下吗?当你说a=1;b=2;商店不保证按这种顺序进行。当涉及到非同步操作的排序时,ECMA几乎不提供任何保证。假设操作的发生顺序与源语言(C#)定义的顺序相同,这是一个常见的错误。尤其是在这里,即使列表内容发生在发布列表之前,也不能保证它们是可见的。对于那些投票支持“主要基于意见”的人,请注意,我想问的是,这种行为是否有好的原因,这不是基于意见的问题。因为我花了很长时间才意识到实际的区别是什么,对于同样感到困惑的人,这里有一个提示:
mContainers
的初始值设定项正在引用自身,但在当时,引用仍然是
null
。没有临时列表。有一个临时变量。不过,该变量不是对象。这是一个参考。+1表示“原子操作”,这有点奇怪,因为列表初始化本质上并不是一个原子操作,但我想让它实际上是原子的。@FabioSalvalai这只是同一个列表;只有一个列表对象。它不是一个临时变量,真的,你是对的。这是某种“减压”
var __clist = new List<Contact>();
// …
__clist.Add(__c1);
// …
__clist.Add(__c2);
var contacts = __clist;
SomeMethodCall(new List<int>() { 1, 2, 3 });