【问题标题】:How does the IDE/Compiler know that a lambda expression is executed immediately and not saved for later use?IDE/编译器如何知道 lambda 表达式是立即执行的,而不是保存供以后使用的?
【发布时间】:2018-01-11 16:42:18
【问题描述】:

编译器(我在这里松散地使用这个词,我的 VS、Roslyn、R# 工具链中的某个人)知道当我访问 lambda 表达式中的变量时,如果稍后执行可能已经被释放。这是一个很棒的功能,也是一个受欢迎的警告。但是,有时我知道 lambda 表达式会立即执行,而不是保存以供以后使用,所以这个警告是错误的。

有人可能会争辩说,编译器无法知道 lambda 表达式是否已执行或保留以供以后使用。有趣的事实:确实如此。如果我在 LinQ 语句中使用它,我会得到一条弯曲的警告线,except,因为当我立即通过调用 .ToList() 来实现该事物时。然后警告消失。因此,编译器知道 lambda 是被使用过一次然后被丢弃,还是保留以备后用。

使用波浪线访问已处置的闭包:

我如何向我的工具链解释我的方法(采用 lambda 的 .ThrownFrom() 实际上是立即执行它并且不保留对它的引用?

我能否通过属性、模式或其他我可以设置的东西获得与物化 LinQ 相同的效果,或者是某些特定于 LinQ 的硬编码编译器魔法?


以我的忽略类为例:

public static class Ignore<TException> where TException : Exception
{
    public static void ThrownFrom([NotNull] Action action)
    {
        if (action is null)
        {
            throw new ArgumentNullException(nameof(action));
        }

        try
        {
            action();
        }
        catch (TException ex)
        {
            // ignore
        }
    }
}

【问题讨论】:

  • 然后关掉R#;)
  • 您可以在 // ReSharper disable once AccessToDisposedClosure 行前添加注释来禁用此功能。不过感觉有点恶心。

标签: c# lambda compiler-warnings code-analysis


【解决方案1】:

有人可能会争辩说,编译器无法知道 lambda 表达式是被执行还是保留以供以后使用。

这样的论点是正确的。它假设任何 lambda 都可以在应用程序未来的任何时间点被调用,并相应地编译代码。

有趣的事实:确实如此。如果我在 LinQ 语句中使用它,我会得到一条曲折的警告线,除非我立即通过调用 .ToList() 来实现该事物。然后警告消失。所以编译器知道一个 lambda 是被使用过一次然后被丢弃,还是保留供以后使用。

不,编译器不会做这样的事情。一些代码分析工具试图确定是否可以在给定范围之外调用给定的 lambda,但它们不知道。在一般情况下不可能知道,但您有时可以在某些特定情况下知道。他们只是硬编码了一堆他们知道或不知道是否立即调用 lambda 的特定情况(在这种情况下,他们只是将某些框架的事实硬编码到代码分析工具中方法立即调用提供的委托,其他方法稍后保留它)。鉴于此,他们有时会犯错误,因为有很多方法他们根本无法知道委托是否被保留。

我如何向我的工具链解释我的方法(采用 lambda 的 .ThrownFrom())实际上是立即执行它并且不保留对它的引用?

您可以查看文档以了解您使用的任何代码分析工具。他们可能会提供这样做的方法,也可能不会。

【讨论】:

  • 我同意这个:)
  • Holy Murphy... 事实证明,在我尝试 google 三天后,如果我只是打开我的代码分析工具针对此警告建议的帮助页面,它就在那里。掌心。谢谢:)
【解决方案2】:

事实证明,@Servy 的答案是绝对正确的(不足为奇),我的问题的解决方案实际上是在我的代码分析工具的帮助页面上,仅针对该警告(令人惊讶):

如果您使用的是 Resharper(会生成此警告),您可以使用 [InstantHandle] 属性来表示此 lambda 表达式实际上已被立即处理。

所以:

public static class Ignore<TException> where TException : Exception
{
    public static void ThrownFrom([InstantHandle][NotNull] Action action)
    {
        if (action is null)
        {
            throw new ArgumentNullException(nameof(action));
        }

        try
        {
            action();
        }
        catch (TException ex)
        {
            // ignore
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-18
    • 1970-01-01
    • 1970-01-01
    • 2023-02-24
    • 1970-01-01
    • 2014-01-11
    相关资源
    最近更新 更多