我最初有一些代码,在简化后,看起来像这样:
var planets = new List<Planet>
{
new Planet {Id = 1, Name = "Mercury"},
new Planet {Id = 2, Name = "Venus"},
};
我进入了一个列表正在一次填充的场景,但读取速度不够快。因此,我将其更改为使用SortedList。
我后来意识到我可以像这样重写它
var planets = new SortedList<int, Planet>
{
{1, new Planet {Id = 1, Name = "Mercury"}},
{2, new Planet {Id = 2, Name = "Venus"}},
//in my actual code, i am reading the ids from a db
};
但在我采用这种方法之前,我的代码就像这样写了
var planets = new SortedList<int, Planet>
{
Keys = {1, 2},
Values =
{
new Planet {Id = 1, Name = "Mercury"},
new Planet {Id = 2, Name = "Venus"},
}
};
给了我这个例外
System.NotSupportedException: This operation is not supported on SortedList
nested types because they require modifying the original SortedList.
at System.ThrowHelper.ThrowNotSupportedException(ExceptionResource resource)
at System.Collections.Generic.SortedList`2.KeyList.Add(TKey key)
我觉得很奇怪,因为恕我直言,我并没有真正修改原来的SortedList&#34;正如它声称的那样,以及#34;嵌套类型&#34;它在说什么?它是SortedList
内部的键列表吗?
我看到Keys
中的Values
和SortedList
属性实际上并没有设置者。它们是只读属性,但是,我没有得到编译时错误。我可以进行一次固定调用,我可以在堆栈跟踪中看到KeyList.Add
。我觉得失败的唯一原因是因为SortedList
内的明确检查,这对我来说似乎很奇怪!
例如
var str = new String {Length = 0};
按预期给出了编译时错误,因为Length是只读属性,planets.Keys = null;
有人请告诉我 - 我在这里看到了什么简单的事实?
答案 0 :(得分:3)
您编写的代码与此类似:
var planets = new SortedList<int, Planet>();
planets.Keys.Add(1);
planets.Keys.Add(2);
planets.Values.Add(new Planet { Id = 1, Name = "Mercury" });
planets.Values.Add(new Planet { Id = 2, Name = "Venus" });
SortedList
要求您通过SortedList<TKey, TValue>.Add(TKey key, TValue value)
方法同时添加值和键,以便它可以按键对值进行排序。内部用于IList<T>
和Keys
的{{1}}的实施不支持通过Values
方法单独添加相应的键或值。
您应该可以通过调用IList<T>.Add(T value)
或Keys.Add(...)
答案 1 :(得分:0)
我对SortedList
的初步查询现已最小化了对阵列,集合和放大器的关注。对象初始值设定项,以及编译器以不同方式解释它们的方式。再次感谢@Haney第一个引导我走向这一观点的答案,并感谢ILSpy了解这些见解。
以下是一些数组和集合初始值设定项:
int[] a = { 1, 2, 3 };
int[] b = new int[] { 1, 2, 3 };
IList<int> c = { 1, 2, 3 };
IList<int> d = new int[] { 1, 2, 3 };
他们看起来都很相似。在这里,编译器为&amp;产生完全相同的输出。湾对于c,我们将得到这个编译时错误:
只能使用数组初始值设定项表达式来分配数组类型。 请尝试使用新表达式。
这是有道理的,因为我们不应该为集合使用数组初始值设定项。但是,然后,d产生的结果与&amp;湾我认为这也是一个数组初始化器。显然不是。
现在考虑这个课程
class MyCollectionContainer
{
public int[] MyIntArray { get; set; }
public IList<int> MyList { get; set; }
}
以及在其上运行的代码
var containerA = new MyCollectionContainer { MyIntArray = { 1, 2, 3 } };
var containerB = new MyCollectionContainer { MyIntArray = new int[]{ 1, 2, 3 } };
var containerC = new MyCollectionContainer { MyList = { 1, 2, 3 } };
var containerD = new MyCollectionContainer { MyList = new int[]{ 1, 2, 3 } };
containerA给出了这个编译时错误:
无法初始化类型&#39; int []&#39;使用集合初始值设定项
对于containerB,编译器有效地将其转换为此代码:
MyCollectionContainer myCollectionContainer = new MyCollectionContainer();
myCollectionContainer.MyIntArray = new int[] {1, 2, 3};
对于containerD,它几乎是一样的,除非它的另一个属性被初始化:
MyCollectionContainer myCollectionContainer = new MyCollectionContainer();
myCollectionContainer.MyList = new int[] {1, 2, 3};
对于containerC,编译器将其变形为:
MyCollectionContainer myCollectionContainer = new MyCollectionContainer();
myCollectionContainer.MyList.Add(1);
myCollectionContainer.MyList.Add(2);
myCollectionContainer.MyList.Add(3);
由于NullReferenceException
未初始化,因此会产生运行时MyList
。
这意味着在这里初始化集合容器对象的唯一有效方法是containerB和containerD。对我来说,这清楚地表明,与阵列和数据相比,对象初始化器是不同的。集合初始值设定项,以编译器解释它们的方式。