是否可以在选择中调用重方法

本文关键字:调用 方法 选择 是否 | 更新日期: 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