只读集合属性的C#对象初始化
就我个人而言,我无法理解下面的示例C#代码中发生了什么。测试类的collection(List)属性设置为只读,但我似乎可以在对象初始值设定项中为其赋值 **编辑:修复了列表“getter”的问题只读集合属性的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<
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”}
只是一个赋值,没有对象创建表达式。