在C#中动态解压缩IEnumerable或最佳替代方案
让我们假设您有一个函数返回一个延迟枚举的对象:
struct AnimalCount { int Chickens; int Goats; } IEnumerable FarmsInEachPen() { .... yield new AnimalCount(x, y); .... }
您还有两个使用两个独立IEnumerable
的函数,例如:
ConsumeChicken(IEnumerable); ConsumeGoat(IEnumerable);
如何在没有a)事先转换FarmsInEachPen()
ToList()的情况下调用ConsumeChicken
和ConsumeGoat
,因为它可能有两个zillion记录,b)没有multithreading。
基本上:
ConsumeChicken(FarmsInEachPen().Select(x => x.Chickens)); ConsumeGoats(FarmsInEachPen().Select(x => x.Goats));
但是没有强制双重枚举。
我可以使用multithreading来解决它,但是每个列表的缓冲队列都会变得不必要地复杂化。
所以我正在寻找一种方法将AnimalCount
枚举器分成两个int
枚举器而不完全评估AnimalCount
。 在锁步中一起运行ConsumeGoat
和ConsumeChicken
没有问题。
我能够完全理解解决方案,但我并不在那里。 我正在考虑一个辅助函数,它返回一个IEnumerable
被输入到ConsumeChicken
,每次使用迭代器时,它在内部调用ConsumeGoat
,从而在锁步中执行这两个函数。 当然,除了我不想多次打电话给ConsumeGoat
..
我不认为有办法做你想要的,因为ConsumeChickens(IEnumerable
和ConsumeGoats(IEnumerable
被顺序调用,每个人都单独枚举一个列表 – 你怎么期望工作没有两个单独的列表枚举?
根据具体情况,更好的解决方案是使用ConsumeChicken(int)
和ConsumeGoat(int)
方法(每个方法都使用一个项目) ,并交替调用它们。 像这样:
foreach(var animal in animals) { ConsomeChicken(animal.Chickens); ConsomeGoat(animal.Goats); }
这将只列举animals
集合一次。
另外,注意:取决于您的LINQ提供商以及您正在尝试做什么,可能有更好的选择。 例如,如果您尝试使用linq-to-sql或linq-to-entities从数据库获取鸡和山羊的总和,则以下查询..
from a in animals group a by 0 into g select new { TotalChickens = g.Sum(x => x.Chickens), TotalGoats = g.Sum(x => x.Goats) }
将导致单个查询,并在数据库端进行求和,这比将整个表拉过并在客户端进行求和更为可取。
你提出问题的方式,没有办法做到这一点。 IEnumerable
是一个可枚举的拉 – 也就是说,你可以将GetEnumerator
放到序列的前面,然后反复询问“给我下一个项目”( MoveNext
/ Current
)。 在一个线程中,你不能从animals.Select(a => a.Chickens)
那里得到两个不同的东西animals.Select(a => a.Chickens)
和animals.Select(a => a.Chickens)
animals.Select(a => a.Goats)
同时。 你必须做一个然后另一个(这需要实现第二个)。
BlueRaja提出的建议是一种稍微改变问题的方法。 我建议走那条路。
另一种方法是利用微软的反应式扩展(Rx)中的IObservable
, 推送可枚举 。 我不会详细介绍你将如何做到这一点,但这是你可以研究的东西。
编辑:
以上假设ConsumeChickens
和ConsumeGoats
都返回void
或至少不返回IEnumerable
本身 – 这似乎是一个明显的假设。 如果蹩脚的下行者真的会发表评论,我会很感激。
实际上简单的方法来实现你将什么转换为FarmsInEachPen返回值来推送集合或IObservable并使用ReactiveExtensions来处理它
var observable = new Subject() observable.Do(x=> DoSomethingWithChicken(x. Chickens)) observable.Do(x=> DoSomethingWithGoat(x.Goats)) foreach(var item in FarmsInEachPen()) { observable.OnNext(item) }
我想通了,谢谢很大程度上归功于@Lee让我走的路。
您需要在两个拉链之间共享一个枚举器,并使用适配器函数将正确的元素投影到序列中。
private static IEnumerable