如何使用 C# 中的索引从 IEnumerable 集合中获取项目?

How to get item from IEnumerable collection using its index in C#?

我有 IEnumerablecustomerList 列表和索引。现在我想根据索引获取 IEnumerable 的项目。

例如,如果 index = 3,它应该为我提供 IEnumerable 的第 3 项。

请指导。

IEnumerable<Customer> customerList = new Customer[] 
{ 
     new Customer { Name = "test1", Id = 999 }, 
     new Customer { Name = "test2", Id = 915 }, 
     new Customer { Name = "test8", Id = 986 },
     new Customer { Name = "test9", Id = 988 },
     new Customer { Name = "test4", Id = 997 },
     new Customer { Name = "test5", Id = 920 },
};

int currentIndex = 3;   //want to get object Name = "test8", Id = 986

For example, if index = 3, it should provide me 3rd item of the IEnumerable

您知道 .NET 中的索引是基于零的吗?但是,您可以使用 ElementAt:

Customer c = customerList.ElementAt(currentIndex); // 4th

使用ElementAtOrDefault来防止如果没有足够的项目出现异常,那么你会得到null:

Customer c = customerList.ElementAtOrDefault(currentIndex); // 4th or null

这些方法以使用 IList<T> indexer 的方式进行了优化。因此,在您的示例中,实际上有一个 Customer[] 实现了该接口,因此它将使用索引器。

如果序列没有实现IList<T>,它将被枚举以在该索引处找到项目。

如果您想要基于索引的访问,请不要 使用 IEnumerable。使用 IList 代替:

IList<Customer> customerList = new Customer[] 
{ 
 new Customer { Name = "test1", Id = 999 }, 
 new Customer { Name = "test2", Id = 915 }, 
 new Customer { Name = "test8", Id = 986 },
 new Customer { Name = "test9", Id = 988 },
 new Customer { Name = "test4", Id = 997 },
 new Customer { Name = "test5", Id = 920 },
};

对于 IEnumerable,唯一的选择是使用 ElementAt() 扩展方法。

IEnumerable<T> 只保证一个集合可以被枚举。它没有关于访问元素的其他承诺。 ElementAt 允许通过枚举 一次访问一个集合中的特定元素,直到达到所需的元素。那可能很贵。

幸运的是,ElementAt checks to see whether the argument is an IList 并尽可能使用基于索引的访问。

但这并不意味着您应该使用 IEnumerable<T>。它会让不知道变量背后的实际实例是什么的维护者(包括你)感到困惑。如果 不是 IList 的东西曾经分配给该变量

,它也会导致性能问题

IEnumerable 是一种 'streaming' 数据类型,因此可以将其视为流而不是数组。

var yourCustomer = customerList.Skip(2).First()

但是,如果您想要更像数组的语法,IList 可能是您用例的更好抽象。

这可以使用 ElementAt 方法实现。

如果你的IEnumerable不是物化集合,而是一个生成序列,多次调用ElementAt方法会导致多次生成序列。这通常是不希望的,因为它会不必要地消耗资源。

上面的一些答案建议使用 IList 而不是 IEnumerable。是的,它肯定会使通过索引访问变得不那么麻烦,但是使用 IList 有一个令人讨厌的副作用,它会使集合可变。我会改用 IReadOnlyList

IReadOnlyList<Customer> customerList = new Customer[]
{
    new Customer { Name = "test1", Id = 999 },
    new Customer { Name = "test2", Id = 915 },
    new Customer { Name = "test8", Id = 986 },
    new Customer { Name = "test9", Id = 988 },
    new Customer { Name = "test4", Id = 997 },
    new Customer { Name = "test5", Id = 920 },
};

int currentIndex = 3;   //want to get object Name = "test8", Id = 986

var result = customerList[currentIndex];
customerList.Add(new Customer()); // doesn't compile
customerList[currentIndex] = new Customer(); // doesn't compile