Why can I access an item in KeyCollection/ValueCollection by index even if it doesn't implement IList(Of Key)?
我注意到一个奇怪的vb.net东西。从这个问题出发,我提供了一种通过索引访问字典的
下面是一个简单的例子:
1 2 3 4 5 6 7 | Dim sortedDict As New SortedDictionary(Of DateTime, String) sortedDict.Add(DateTime.Now,"Foo") Dim keys As SortedDictionary(Of DateTime, String).KeyCollection = sortedDict.Keys Dim values As SortedDictionary(Of DateTime, String).ValueCollection = sortedDict.Values Dim firstkey As DateTime = keys(0) Dim firstValue As String = values(0) |
但令我惊讶的是,问题的提问者说它不编译,而它编译并为我工作却没有问题:
1 | System.Diagnostics.Debug.WriteLine("Key:{0} Value:{1}", firstkey, firstValue) ' Key:04/29/2016 10:15:23 Value:Foo |
号
所以,如果
请注意,它是一个全新的控制台应用程序,内部没有扩展。我也不能使用索引器的定义(也不能使用Resharper)。为什么它对我有用?
旁注:它不适用于C。我得到预期的编译器错误:
Cannot apply indexing with [] to an expression of type
'SortedDictionary.KeyCollection'
号
1 2 3 | var dict = new SortedDictionary<DateTime, string>(); dict.Add(DateTime.Now,"Foo"); DateTime dt = dict.Keys[0]; // here |
下面是编译vb.net代码的屏幕截图:
。
它调用
1 2 3 4 5 | // [10 13 - 10 31] IL_001f: ldloc.1 // keys IL_0020: ldc.i4.0 IL_0021: call !!0/*valuetype [mscorlib]System.DateTime*/ [System.Core]System.Linq.Enumerable::ElementAtOrDefault<valuetype [mscorlib]System.DateTime>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0/*valuetype [mscorlib]System.DateTime*/>, int32) IL_0026: stloc.2 // firstKey |
此行为记录在Visual Basic语言规范11.21.3中:
Every queryable collection type whose element type is
T and does not already have a default property is considered to have a default property of the following general form:
1
2
3
4
5 Public ReadOnly Default Property Item(index As Integer) As T
Get
Return Me.ElementAtOrDefault(index)
End Get
End PropertyThe default property can only be referred to using the default property access syntax; the default property cannot be referred to by name. For example:
1
2
3
4
5 Dim customers As IEnumerable(Of Customer) = ...
Dim customerThree = customers(2)
' Error, no such property
Dim customerFour = customers.Item(4)If the collection type does not have an
ElementAtOrDefault member, a compile-time error will occur.
号
当我们使用Enumerable.elementorDefault或Enumerable.elementat时,会有相当大的性能成本。除非源实现了ilist(of t)接口,否则linq没有较短的路径来到达指定索引处的元素。所以它迭代每个元素,直到迭代计数达到指定索引的值。没有魔法。可枚举。count()具有相同的情况,但在本例中,ICollection接口(如果由源实现)除外,Linq将获取它,否则将进行迭代,直到需要最后一个元素来生成count为止。我不知道为什么vb.net会隐式地允许它,因为在我面临严重的性能问题之前,这样的情况很可能不会被注意到。字典只实现ICollection而不是IList。我认为人们需要小心使用vb.net,因为它不像C那样严格地输入语言。