CS9236 编译需要绑定 lambda 表达式至少 100 次

问题描述 投票:0回答:1

我最近在 C# 中看到以下编译器消息:

CS9236 编译需要绑定 lambda 表达式至少 100 次。考虑使用显式参数类型声明 lambda 表达式,或者如果包含的方法调用是泛型,请考虑使用显式类型参数。

不幸的是,帮助链接(当前)已损坏。您能用例子解释一下吗?为什么使用显式类型来膨胀表达式是个好主意?

取自测试的示例:

using System.Linq;
class Container
{
    public IEnumerable<Container> Items;
    public int Value;
}
class Program
{
    static void Main()
    {
        var list = new List<Container>();
        _ = list.Sum(
            a => a.Items.Sum(
                b => b.Items.Sum(
                    c => c.Value)));
    }
}
c#
1个回答
0
投票

首先,据我所知,这些消息仅显示在 Visual Studio 中 - 很可能有一种方法可以让

dotnet build
报告它们,但我还没有找到。

该示例可以稍微简化,仅使用两个 lambda 表达式:

#pragma warning disable 649
class Container
{
    public IEnumerable<Container> Items;
    public int Value;
}
class Program
{
    static void Main()
    {
        var list = new List<Container>();
        _ = list.Sum(
            a => a.Items.Sum(
                b => b.Value));
    }
}

这只会产生一条消息,但更容易理解。

该消息与代码是否有效无关 - 它实际上只是说“嘿,这导致编译器做很多工作 - 你可以让它的生活更轻松。”在某些情况下,这反过来又可以减少编译时间。

发生这种情况的原因是 C# 的两个最棘手的方面(从规范角度来看,我怀疑从编译器实现角度来看):

  • 泛型类型推断
  • 过载解决方案

特别是,虽然 C# 中的大多数表达式自然都有类型,但对于 lambda 表达式,编译器必须有效地查看它是否可以将给定的 lambda 表达式转换为候选参数类型,以便检查每个重载的适用性。当存在嵌套 lambda 时,这意味着整个过程最终会呈指数级增长。

Sum
导致这一问题(比如说)
Select
不会导致这个问题的原因是
Sum
有很多重载
——即使你用多个参数删除了重载。

此示例中的 message 有点令人困惑,因为指定 lambda 表达式参数类型和类型参数没有帮助。这仍然给出相同的消息,例如:

_ = list.Sum<Container>(
    (Container a) => a.Items.Sum<Container>(
        (Container b) => b.Value));

告诉编译器 lambda 表达式的目标类型是完全可行的:

_ = list.Sum(
    a => a.Items.Sum(
        (Func<Container, int>) (b => b.Value)));

或者您可以选择使用局部变量以不同的方式实现它:

var valueSelector = (Container b) => b.Value;
_ = list.Sum(
    a => a.Items.Sum(valueSelector));

Func<Container, int> valueSelector = b => b.Value;
_ = list.Sum(
    a => a.Items.Sum(valueSelector));

(或使用本地函数。)

所有这些基本上都使编译器的工作变得更轻松,可能会缩短编译时间。如果编译时间对您来说不是问题并且您不想更改代码,则可以隐藏该消息。该消息只是为了让编译器可以帮助解释为什么需要这么长时间。

© www.soinside.com 2019 - 2024. All rights reserved.