为什么我可以将索引器应用于VB.Net中的ICollection,而不是C#中
将一些代码从VB.Net转换为C#,当我遇到这个时,在使用Ionic Zip库的一些代码中:
Dim zipEntry1 As ZipEntry = zipFile1.Entries(0)
很简单:
ZipEntry zipEntry1 = zipFile1.Entries[0];
我在C#上遇到这个错误:
无法将带有[]的索引应用于类型为“System.Collections.Generic.ICollection”的表达式
两者都使用相同版本的DLL,在两个zipFile1.Entries
都是一个通用的ICollection
。
我在VB.Net上测试了下面的内容,它成功构建:
Option Strict On Option Explicit On Imports Ionic.Zip Module Module1 Sub Main() Dim zipFile1 = ZipFile.Read("C:\test") Dim zipEntry = zipFile1.Entries(0) End Sub End Module
这不构建:
using Ionic.Zip; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { var zipFile1 = ZipFile.Read(@"C:\test"); var zipEntry = zipFile1.Entries[0]; } } }
为什么会发生这种情况,有没有解决方法呢?
奇怪的是,看起来VB对IEnumerable
有特殊支持,并且隐式提供了一个实际调用Enumerable.ElementAtOrDefault
的索引器。 ICollection
扩展了IEnumerable
,因此存在相同的工具。 ICollection
不提供“真正的”索引器,因此当您尝试从C#使用它时会出现问题。
示例程序:
Option Strict On Public Class Test Public Shared Sub Main(args As String()) Dim x as System.Collections.Generic.ICollection(Of String) = args Console.WriteLine(x(0)) End Sub End Class
生成的主要IL:
.method public static void Main(string[] args) cil managed { .entrypoint .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) // Code size 15 (0xf) .maxstack 2 .locals init (class [mscorlib]System.Collections.Generic.IEnumerable`1 V_0) IL_0000: ldarg.0 IL_0001: stloc.0 IL_0002: ldloc.0 IL_0003: ldc.i4.0 IL_0004: call !!0 [System.Core]System.Linq.Enumerable::ElementAtOrDefault ( class [mscorlib]System.Collections.Generic.IEnumerable`1, int32) IL_0009: call void [mscorlib]System.Console::WriteLine(string) IL_000e: ret } // end of method Test::Main
我发现VB隐含地提供这一点非常奇怪 – 让它看起来像索引到一个不一定提供有效索引操作的集合是很好的。
当然,如果你ElementAtOrDefault
感到满意,你可以自己调用ElementAtOrDefault
。
严格来看, ICollection
是无序元素集合的接口(更准确地说,是一个集合,其元素不能通过索引单独访问)。 这只是定义 。
但是你仍然可以使用LINQ的ElementAt(int index)
扩展方法。 这会在每次调用它时迭代所有元素index
时间(因此通常较慢)。
注意:不要将ICollection
与Collection
混淆。 后者实现了IList
(以及其他内容),根据定义,它确实指定每个元素都可以通过其索引访问。
VB长期以来一直想到它的类的默认成员 ,对于集合来说,它总是成员Item ()。