是否可以在选择中调用重方法
本文关键字:调用 方法 选择 是否 | 更新日期: 2023-09-27 18:35:53
我需要处理数据库中的几个项目,并将JSON字符串中的处理状态发送回调用方。我写了这样的东西(简化):
string ProcessAll()
{
return ConvertToJsonString(
database.
Get<XAccount>().
Where(a => a.Enabled).
Select(a => new
{
Id = a.Id,
Success = HeavyProcessing(a)
}).
ToArray());
}
bool HeavyProcessing(XAccount account)
{
try
{
.... up to 10-20 HTTP requests here ......
return true;
}
catch (Exception ex)
{
LogException(ex);
return false;
}
}
HeavyProcessing
相当复杂:在内部它执行大量HTTP请求。可以用Select
打电话吗?如果没有,我怎样才能优雅地重新设计ProcessAll
?
我的另一个想法是创建IEnumerable<XAccountStatus> HeavyProcessAll(IEnumerable<XAccount> accounts)
方法,并在其中使用return yield
。在重型方法中使用yield
可以吗?
这不会有太大区别,因为无论如何,您在调用Select
后立即调用ToArray
,因此您需要等待所有项目被处理,然后才能继续进一步执行。
可以考虑使用并行执行和 PLINQ 同时对多个项目执行这些繁重的操作。 AsParallel
应该使诀窍:
string ProcessAll()
{
return ConvertToJsonString(
database.
Get<XAccount>().
Where(a => a.Enabled).
AsParallel().
Select(a => new
{
Id = a.Id,
Success = HeavyProcessing(a)
}).
ToArray());
}
非常聪明的问题。我不相信 LINQ to Objects 指定了确切的执行模式。不能正式保证每个项目仅按顺序调用一次选择器。如果您只依赖于文档所做的形式保证,则必须假设您的"重型"选择器函数可能会运行多次或无序运行。
现在显然这不是Enumerable.Select
所做的。几乎只有一个合理的实现可能:
foreach (var item in items) yield return selector(item);
我愿意在我的项目中依赖这一事实,我向其他人推荐同样的事实。
鉴于我们现在拥有(或假设)LINQ 如何运行查询的可执行模型,我们可以看到使用 LINQ 运行繁重的选择器确实是安全的。
一个可能的复杂情况是惰性求值,但您已通过使用 ToArray
具体化序列来排除这种可能性。
还要考虑 LINQ 在代码质量方面带来的好处。
按照问题中的建议使用yield return
编写自定义函数基本上会产生相同的结果。如果你把你的处理代码内联到上面给出的代码片段中(用它替换selector
),你就会得到你的建议。没必要那样做。
你说的是实体框架吗?我很确定它不会以这种方式工作。EF 不知道如何将HeavyProcessing
转换为 SQL 查询,你将在运行时收到异常。因此,您必须先从数据库中获取所有XAccount
项目,然后在每个项目上应用HeavyProcessing
。