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

标签 c# .net list compilation initialization

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

我有以下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> ,所以我可以这样实现:

//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,并看到了以下代码:

MSIL lists

现在,这解释了问题发生的原因,我什至查看了 CSharp 语言规范 文档,这是定义的行为:

A List can be created and initialized as follows:

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" }
    }
};

which has the same effect as

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;

where __clist, __c1 and __c2 are temporary variables that are otherwise invisible and inaccessible.

很明显这种行为是有意为之的。一切都在临时变量而不是原始变量上完成,是否有充分的理由?因为这对我来说似乎是一种错误的行为。

最佳答案

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

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

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

关于c# - 是否应该将此列表初始值设定项行为报告为 Visual Studio C# 编译器中的错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32921469/

相关文章:

.net - Linq 将复杂类型聚合成一个字符串

c# - 如何使用值从字典中删除条目

list - 有效地检查(大)列表的所有元素是否相同

list - 为什么从列表中切片元素不返回列表?

c# - 从用户界面调用System.Threading.Thread时,锁将挂起。

c# - 禁用组合框中的特定项目

c# - Fusion loader 找不到实际存在的 DLL

c# - 使用 Powershell 创建 ConfigMgr 应用程序时图标质量不佳

Python:列表索引超出范围/追加列表

c# - 查找未声明的命名空间前缀