这似乎是一个愚蠢的问题,但我没有找到答案,所以在这里。 :)
在这两种情况下,如果您未能检查集合的范围,您将获得“超出范围”的异常。这只是编码风格偏好吗?
如果有人需要一个例子:
List<byte> myList = new List<byte>(){0x01, 0x02, 0x03};
byte testByte = myList.ElementAt(2);
与
byte testByte = myList[2];
答案 0 :(得分:25)
因为Enumerable
更通用,而且由enumerable表示的集合可能没有索引器。
但是,如果确实如此 - 不要使用ElementAt()
它可能不会那么有效。
答案 1 :(得分:18)
ElementAt()
为C#中的所有枚举提供统一的界面。我倾向于经常使用它,因为我喜欢常见的API。
如果基础类型支持随机访问(即,它支持[]
运算符),则ElementAt将使用它。因此,唯一的开销是额外的方法调用(几乎从不相关)。
如果基础类型不支持随机访问,则ElementAt()
通过迭代枚举来模拟它,直到它到达您关心的元素。这可能非常昂贵,甚至有时会产生副作用。
还有ElementAtOrDefault()
通常非常方便。
答案 2 :(得分:8)
更新:我觉得这是一个有趣的话题,并决定blog about it。
基本上,我的观点是,在没有需要IList<T>
的情况下,将抽象用于随机访问很少有意义。如果您正在编写想要通过索引随机访问集合元素的代码,那么只需要一个能够为您提供的代码。如果您需要IList<T>
开头,我真的认为使用ElementAt
代替索引器毫无意义。
但那当然是我的意见。
请勿将其用于IList<T>
或T[]
等List<T>
实施。只有当您 指向不提供随机访问权限的集合类型时才使用它,例如Queue<T>
或Stack<T>
。
var q = new Queue<int>();
var s = new Stack<int>();
for (int i = 0; i < 10; ++i)
{
q.Enqueue(i);
s.Push(i);
}
// q[1] would not compile.
int fromQueue = q.ElementAt(1);
int fromStack = s.ElementAt(1);
答案 3 :(得分:8)
在某些情况下使用ElementAt()避免!!!
如果您知道自己要查找每个元素,并且已经(或可能有)超过500,那么只需调用ToArray(),将其存储在可重用的数组变量中,然后将其编入索引
例如;我的代码是从Excel文件中读取数据 我正在使用ElementAt()来查找我的Cell引用的SharedStringItem 如果有500行或更少的线路,您可能不会注意到差异 有16K线,需要100秒。
为了使事情变得更糟(它读取的每一行),索引增长得越大,每次迭代所需的索引就越多,因此花费的时间比它应该的要长。
前1,000行需要2.5秒,而最后1,000行需要10.7秒。
循环使用这行代码:
SharedStringItem ssi = sst.Elements<SharedStringItem>().ElementAt(ssi_index);
导致此记录输出:
...Using ElementAt():
RowIndex: 1000 Read: 1,000 Seconds: 2.4627589
RowIndex: 2000 Read: 1,000 Seconds: 2.9460492
RowIndex: 3000 Read: 1,000 Seconds: 3.1014865
RowIndex: 4000 Read: 1,000 Seconds: 3.76619
RowIndex: 5000 Read: 1,000 Seconds: 4.2489844
RowIndex: 6000 Read: 1,000 Seconds: 4.7678506
RowIndex: 7000 Read: 1,000 Seconds: 5.3871863
RowIndex: 8000 Read: 1,000 Seconds: 5.7997721
RowIndex: 9000 Read: 1,000 Seconds: 6.4447562
RowIndex: 10000 Read: 1,000 Seconds: 6.8978011
RowIndex: 11000 Read: 1,000 Seconds: 7.4564455
RowIndex: 12000 Read: 1,000 Seconds: 8.2510054
RowIndex: 13000 Read: 1,000 Seconds: 8.5758217
RowIndex: 14000 Read: 1,000 Seconds: 9.2953823
RowIndex: 15000 Read: 1,000 Seconds: 10.0159931
RowIndex: 16000 Read: 1,000 Seconds: 10.6884988
Total Seconds: 100.6736451
一旦我创建了一个中间数组来存储SharedStringItem以进行引用,我的时间就会缩短到100秒,然后在相同的时间内处理每一行。
这行代码:
SharedStringItem[] ssia = sst == null ? null : sst.Elements<SharedStringItem>().ToArray();
Console.WriteLine("ToArray():" + watch.Elapsed.TotalSeconds + " Len:" + ssia.LongCount());
并循环使用这行代码:
SharedStringItem ssi = ssia[ssi_index];
导致此记录输出:
...Using Array[]:
ToArray(): 0.0840583 Len: 33560
RowIndex: 1000 Read: 1,000 Seconds: 0.8057094
RowIndex: 2000 Read: 1,000 Seconds: 0.8183683
RowIndex: 3000 Read: 1,000 Seconds: 0.6809131
RowIndex: 4000 Read: 1,000 Seconds: 0.6530671
RowIndex: 5000 Read: 1,000 Seconds: 0.6086124
RowIndex: 6000 Read: 1,000 Seconds: 0.6232579
RowIndex: 7000 Read: 1,000 Seconds: 0.6369397
RowIndex: 8000 Read: 1,000 Seconds: 0.629919
RowIndex: 9000 Read: 1,000 Seconds: 0.633328
RowIndex: 10000 Read: 1,000 Seconds: 0.6356769
RowIndex: 11000 Read: 1,000 Seconds: 0.663076
RowIndex: 12000 Read: 1,000 Seconds: 0.6633178
RowIndex: 13000 Read: 1,000 Seconds: 0.6580743
RowIndex: 14000 Read: 1,000 Seconds: 0.6518182
RowIndex: 15000 Read: 1,000 Seconds: 0.6662199
RowIndex: 16000 Read: 1,000 Seconds: 0.6360254
Total Seconds: 10.7586264
正如您所看到的,转换为数组只需要一小段时间就可以获得33,560项,并且非常值得加快我的导入过程。
答案 4 :(得分:5)
使用ElementAt()
而不是[]
的唯一原因是,您是否需要IEnumerable
而不是IList
。
答案 5 :(得分:5)
ElementAt()
确实首先尝试转换为IList<T>
然后使用索引器,因此ElementAt()
的性能可能与直接使用索引器的性能没有显着差异。因此,即使您有IList<T>
,也可以考虑ElementAt()
,如果您将来有可能更改声明的类型。
答案 6 :(得分:5)
从语义的角度来看,它们都完全相同。无论你使用哪个都不会改变程序的含义。
您使用[]
:
如果枚举声明为IList<T>
,因为:
a。它更具可读性,惯用性和广泛理解。我使用它的第一个原因。
b。您希望优化每一寸。 []
应该略微更高效,因为它是直接查找并避免强制转换(请注意ElementAt
如果IEnumerable<T>
是IList<T>
则使用索引器ElementAt
,因此不是一个很大的收获)。
c。你还处于.NET 3.5之前的版本。
您使用IEnumerable<T>
:
如果声明的类型仅仅是ElementAt
。
如果var x = GetThatList().ElementAt(1).Wash().Spin().Rinse().Dry();
//is more readable than
var x = GetThatList()[1].Wash().Spin().Rinse().Dry();
使其更具可读性。例如,在流畅的风格电话中:
IList<T>
如果您真的坚持为IEnumerable<T>
和IList<T>
使用一致的风格。
简单来说,如果您将变量声明为[]
,请使用ElementAt
,否则请使用IEnumerable<T>
(我强调“声明”这一点,因为即使您的{{ 1}}下面是IList<T>
,你只能使用ElementAt
。转换为IList<T>
以使用索引器是不行的(无论如何都在ElementAt
内发生))。可读性取得了成功。如果你有这个想法,它很容易选择。在绝大多数情况下,我必须使用索引器样式。我很少被迫使用ElementAt
。
答案 7 :(得分:3)
IEnumerable
不支持直接索引访问,如果你知道你有一个列表,继续使用第二种形式,因为它更容易阅读(可以说)。
ElementAt()
,而不仅仅是列表 - 性能方面,它们在IList
类型(即通用列表)上使用时是相同的,但是如果你有一个列表使用索引访问更具表现力。如果您使用反射器查看ElementAt()
的来源,则会看到如果IEnumerable
的类型为IList
,它将在内部使用索引访问权限:
..
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
return list[index];
}
..