只读集合属性的C#对象初始化

只读集合属性的C#对象初始化,c#,c#-4.0,c#-3.0,C#,C# 4.0,C# 3.0,就我个人而言,我无法理解下面的示例C#代码中发生了什么。测试类的collection(List)属性设置为只读,但我似乎可以在对象初始值设定项中为其赋值 **编辑:修复了列表“getter”的问题 using System; using System.Collections.Generic; using NUnit.Framework; namespace WF4.UnitTest { public class MyClass { private List<

就我个人而言,我无法理解下面的示例C#代码中发生了什么。测试类的collection(List)属性设置为只读,但我似乎可以在对象初始值设定项中为其赋值

**编辑:修复了列表“getter”的问题

using System;
using System.Collections.Generic;
using NUnit.Framework;

namespace WF4.UnitTest
{
    public class MyClass
    {
        private List<string> _strCol = new List<string> {"test1"};

        public List<string> StringCollection 
        {
            get
            {
                return _strCol;
            }
        }
    }

    [TestFixture]
    public class UnitTests
    {
        [Test]
        public void MyTest()
        {
            MyClass c = new MyClass
            {
                // huh?  this property is read only!
                StringCollection = { "test2", "test3" }
            };

            // none of these things compile (as I wouldn't expect them to)
            //c.StringCollection = { "test1", "test2" };
            //c.StringCollection = new Collection<string>();

            // 'test1', 'test2', 'test3' is output
            foreach (string s in c.StringCollection) Console.WriteLine(s);
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用NUnit.Framework;
命名空间WF4.UnitTest
{
公共类MyClass
{
私有列表_strCol=新列表{“test1”};
公共列表集合
{
得到
{
返回(strCol);;
}
}
}
[测试夹具]
公共类单元测试
{
[测试]
公共无效MyTest()
{
MyClass c=新的MyClass
{
//哈?这个属性是只读的!
StringCollection={“test2”,“test3”}
};
//这些东西都不能编译(我不希望它们编译)
//c、 StringCollection={“test1”、“test2”};
//c、 StringCollection=新集合();
//输出“test1”、“test2”、“test3”
foreach(c.StringCollection中的字符串s)Console.WriteLine;
}
}
}

属性
StringCollection
没有设置程序,因此除非添加设置程序,否则无法修改其值。

您没有调用设置程序;您实际上每次都在调用
c.StringCollection.Add(…)
(对于“test2”和“test3”)-它是一个集合初始值设定项。如果将其作为财产转让,则应为:

// this WON'T work, as we can't assign to the property (no setter)
MyClass c = new MyClass
{
    StringCollection = new StringCollection { "test2", "test3" }
};

我认为,如果是只读的,你就不能这样做

c.StringCollection = new List<string>();
c.StringCollection=newlist();
但您可以将项目分配给列表…
我错了吗?

这是:

MyClass c = new MyClass
{
    StringCollection = { "test2", "test3" }
};
翻译为:

MyClass tmp = new MyClass();
tmp.StringCollection.Add("test2");
tmp.StringCollection.Add("test3");
MyClass c = tmp;
它从不试图调用setter——它只是在调用getter的结果上调用
Add
。注意,它也没有清除原始集合

C#4规范第7.6.10.3节对此进行了更详细的描述


编辑:作为一个兴趣点,我有点惊讶于它两次调用getter。我希望它调用getter一次,然后调用
Add
两次。。。规范包括一个示例,演示了这一点。

@remi-查看
get
;每次调用
get
时,它都返回一个集合,其中只有“test1”@markdb314,我已经回答过了。。。每次调用该
get
,代码都会创建一个新列表。您应该将列表作为类中的一个字段。@markdb314:如果您实际使用一个字段(可以通过另一个集合初始值设定项初始化)来支持属性,那么您将得到一个更一致的属性。。。而不是在每次getter调用时创建一个新列表。@markdb314,因为这一行
返回新列表{“test1”}
get
中,它总是返回带有一个元素“test1”的新列表@markdb314:因为集合初始值设定项仅作为对象创建表达式的一部分有效(C#spec第7.6.10节)。这种异常的
get
将导致混淆,顺便说一句,谢谢你给我指出c#spec的那一部分。读完后,我可以看到语法的定义。就我个人而言,我不明白他们为什么要允许这种语法(看起来您正在为属性分配一组新的元素)。。。或者我只是想,因为我最近写了太多的JavaScript:)@markdb314:它之所以存在,是因为它非常有用。允许调用者操作集合但不替换它一点也不奇怪。您解释了为什么不寻常的代码可以工作,但我仍然不理解为什么第一行注释掉的代码不能工作。根据您的解释,我希望
c.StringCollection={“test1”,“test2”}被允许,并且工作方式相同。但是OP说它不能编译。@JesseWebb:集合初始值设定项只允许在对象创建表达式中使用-可以直接在新创建的集合上使用,例如
新列表{“x”、“y”、“z”}
或嵌入在对象初始值设定项中
c.StringCollection={“test1”,“test2”}
只是一个赋值,没有对象创建表达式。