我有一个派生自List<T>
的集合类,需要在该集合的实例上执行打包的action
(即集合太大,所以我想将集合拆分为多个部分,执行部件上的action
。请注意,action有一个类型化的签名,它是一些预定义的方法,它需要一个相同类型的集合。
我知道
target.addRange(source.getRange(start, packageSize);
但这不是我想要的,因为为此我需要一个新的集合实例,并将创建列表条目的副本。因为我知道动作不会以任何方式操纵列表,所以我更喜欢做
之类的事情action(source.Reference(fromIndex, toIndex);
意图不创建列表条目的副本(我知道这些是'仅'参考,但仍有副本。有没有办法在C#中做到这一点?
当然我可以将方法传递给知道如何检索范围的action
,但是操作不需要知道我将执行细分为部分的意图。
答案 0 :(得分:2)
您可以使用LINQ或简单的C#从列表中获取部分,而不是将引用的副本复制到新列表中。
使用Skip
和Take
:
var iterator = source.Skip(start).Take(end - start);
由于它是IEnumerable
,因此您可以在调用的方法中foreach
以上(因此您可能需要更改方法签名):
foreach (var x in iterator)
{
...
}
或者创建自己的状态机。生成的可枚举也可以传递给方法:
private static IEnumerable<T> Take<T>(List<T> source, int start, int end)
{
for (int i = start; i < end; i++)
{
yield return source[i];
}
}
答案 1 :(得分:1)
只需使用Linq:
var notAList = source.Skip(fromIndex).Take(toIndex-fromIndex);
action(notAList);
通过这种方式,您可以创建枚举器,该枚举器将枚举您的数字,而无需为所有数据实例化空间。
答案 2 :(得分:1)
public void MyAction<T>(IEnumerable<T> range)
{
// ...
}
并致电
MyAction(list.Skip(fromIndex).Take(toIndex-fromIndex));
请注意,此运算符(Skip
和Take
)使用延迟执行并评估延迟。所以你确实可以把它想象成源列表中范围的一种引用。
答案 3 :(得分:1)
您可以创建自己的迭代器:
public class MyPartListIterator: IEnumerator
{
private readonly IList list;
private readonly int _startIdx;
private readonly int _endIdx;
private int _current;
public MyIterator(IList list, int start, int end)
{
//do some validations before etc
this._startIdx = this._current = start;
this._endIdx = end;
this._list= list;
}
public bool MoveNext()
{
//do some checks against list was changed
if (this._current >= this._endIdx) return false;
this._current += 1;
}
public object Current => this._list[this._current];
public void Reset() => this._current = this._startidx;
}
然后你可以将迭代器的实例传递给你的action
。
为什么它优于Skip
和Take
?它在启动索引之前不会枚举元素。
您还可以准备课程的通用版本。
从记忆中走出来,没有经过测试。使用C#6.0语法糖。
修改强>
无法将IList<T>
的相同引用传递给您的大ILIst<T>
且仅包含源列表的部分数据。
答案 4 :(得分:0)
您可以在此处使用扩展程序来获取您正在寻找的功能。
public static class ListExtensions
{
public static void PerformActionOnSubset<T>(this IList<T> collection, int fromIndex,
int toIndex, Action<IList<T>> action)
{
action(collection.Skip(fromIndex).Take(toIndex - fromIndex).ToList());
}
}
myCollectionOfSomethings.PerformActionOnSubset(10, 30, myAction);