C# 为什么我可以在VB.Net中对ICollection应用索引器,而不是在C中#
我正在将一些代码从VB.Net转换为C#,当我在使用Ionic Zip库的一些代码中遇到这个问题时:C# 为什么我可以在VB.Net中对ICollection应用索引器,而不是在C中#,c#,vb.net,icollection,C#,Vb.net,Icollection,我正在将一些代码从VB.Net转换为C#,当我在使用Ionic Zip库的一些代码中遇到这个问题时: Dim zipEntry1 As ZipEntry = zipFile1.Entries(0) 很简单: ZipEntry zipEntry1 = zipFile1.Entries[0]; 我在C#上得到了这个错误: 无法将带[]的索引应用于类型为的表达式 'System.Collections.Generic.ICollection' 两者都在zipFile1上使用相同版本的DLL。条目是
Dim zipEntry1 As ZipEntry = zipFile1.Entries(0)
很简单:
ZipEntry zipEntry1 = zipFile1.Entries[0];
我在C#上得到了这个错误:
无法将带[]的索引应用于类型为的表达式
'System.Collections.Generic.ICollection'
两者都在zipFile1上使用相同版本的DLL。条目
是一个通用的i集合
我在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];
}
}
}
为什么会发生这种情况,并且有办法解决吗?严格地看,
ICollection
是无序元素集合的接口(更准确地说,是其元素无法通过索引单独访问的集合)。这只是定义
但是您仍然可以使用LINQ的ElementAt(int-index)
扩展方法。这将在每次调用它时遍历所有元素index
次(因此通常较慢)
注意:
i收藏
不能与收藏
混淆。后者实现了IList
(除其他外),根据定义,它确实指定每个元素都可以通过其索引访问。奇怪的是,看起来VB对IEnumerable
有特殊的支持,并隐式提供了一个实际调用的索引器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<string> 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<string>(
class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>,
int32)
IL_0009: call void [mscorlib]System.Console::WriteLine(string)
IL_000e: ret
} // end of method Test::Main
.method public static void Main(字符串[]args)cil托管
{
.入口点
.custom实例void[mscorlib]System.STAThreadAttribute::.ctor()=(01 00)
//代码大小15(0xf)
.maxstack 2
.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:呼叫!!0
[System.Core]System.Linq.Enumerable::ElementAtOrDefault(
类[mscorlib]System.Collections.Generic.IEnumerable`1,
int32)
IL_0009:调用void[mscorlib]System.Console::WriteLine(字符串)
IL_000e:ret
}//方法测试结束::Main
我觉得很奇怪,VB隐式地提供了这一点——让它看起来很好地索引到一个不一定提供有效索引操作的集合中是非常危险的
当然,您可以自己调用
ElementAtOrDefault
,如果您对它的功能感到满意的话。VB早就有了为其类创建默认成员的想法,而对于集合,默认成员总是成员项()。zipFile1.Entries(0)
调用所谓的默认查询索引器,这是在中定义的鲜为人知的功能:
默认查询索引器
元素类型为T且尚未具有默认属性的每个可查询集合类型都被视为具有以下常规形式的默认属性:
Public ReadOnly Default Property Item(index As Integer) As T
Get
Return Me.ElementAtOrDefault(index)
End Get
End Property
+1对于回答
问题,有没有办法解决呢?
部分,非常感谢,我仍然很想知道原因。@JMK请参阅更新。这只是ICollection
接口的定义方式。@dialer:你的回答没有解释VB为什么允许它(或者它是怎么做的)。我想你不能在C中这样做的想法更多的是C的遗留问题,你可以断言[]
操作符可以使用x86的寻址模式有效地索引序列。而在VB中,你说你想要第三个元素,你得到了第三个元素。@dialer:索引器的提供不一定非常有效,但我不喜欢它是隐式的,没有向调用方表明声明类没有提供它。有时情况可能会更糟——想象一下,如果在索引上使用for循环而不是foreach循环,那么每次到达第n行(或其他任何行)都必须读取文本文件。例如,如果您通过集合
上的索引访问项目,这将变得非常奇怪。这几乎总是与类的索引器相对应,这根本不是VB特有的东西。此线程中演示的“ElementAtOrDefault”的VB快捷方式是特定于VB的怪异事物。在这种情况下,它不是Item,而是ElementAt