在直接调用委托的情况下如何减轻“访问修改的闭包”

Posted

技术标签:

【中文标题】在直接调用委托的情况下如何减轻“访问修改的闭包”【英文标题】:How to mitigate "Access to modified closure" in cases where the delegate is called directly 【发布时间】:2019-05-28 17:53:29 【问题描述】:

我的理解是,当委托可能被存储和稍后调用或在不同的线程上调用时,“访问修改的闭包”警告是警告我从委托访问局部变量,以便局部变量不是在实际代码执行时实际可用。这当然是明智的。

但是,如果我正在创建一个我知道将在同一个线程中立即调用的委托怎么办?然后不需要警告。例如代码中生成警告:

delegate void Consume();

private void ConsumeConsume(Consume c)

    c();


public int Hello()

    int a = 0;

    ConsumeConsume(() =>  a += 9; );

    a = 1;

    return a;

这里不会有问题,因为ConsumeConsume 总是立即调用该函数。有没有办法解决?有什么方法可以注释函数ConsumeConsume 以指示 ReSharper 将立即调用委托?

有趣的是,当我将 ConsumeConsume(() => a += 9; ); 行替换为:

new List<int>(new[] 1).ForEach(i =>  a += 9; );

做同样的事情,不会产生警告。这只是 ReSharper 的一个内置异常,还是我可以做类似的事情来指示立即调用委托?

我知道我可以禁用这些警告,但这不是我们想要的结果。

【问题讨论】:

【参考方案1】:

使用 NuGet 安装 JetBrains.Annotations 包:https://www.nuget.org/packages/JetBrains.Annotations

InstantHandle 属性标记传入的委托。

private void ConsumeConsume([InstantHandle] Consume c)

    c();

来自InstantHandle的描述:

当调用的方法在堆栈上时,告诉代码分析引擎参数是否被完全处理。如果参数是委托,则表示在执行方法的同时执行委托。如果参数是可枚举的,则表示在方法执行时被枚举。

来源:https://www.jetbrains.com/help/resharper/Reference__Code_Annotation_Attributes.html

如果您不想将整个包添加到您的项目中,只需自己添加属性就足够了,尽管我认为这很 hacky。

namespace JetBrains.Annotations

    [AttributeUsage(AttributeTargets.Parameter)]
    public class InstantHandleAttribute : Attribute  

【讨论】:

完美!谢谢。【参考方案2】:

是的,这只是一个警告,您可以通过以下方式缓解它

// ReSharper disable once AccessToModifiedClosure
ConsumeConsume(() =>  a += 9; );

或者在文件级别

// ReSharper disable AccessToModifiedClosure
namespace blah 

或者您可以配置检查严重性,但是我会避免在批发意义上将其关闭,因为它可以发现问题

更新

抱歉,我认为我的问题不够清楚。不得不禁用 无处不在的警告命令对我来说不是一个可接受的解决方案,我 宁愿 ReSharper 找到一些方法来解决它。这 ForEach 示例表明至少有一些现有的 例外。

您可以将其关闭,但不幸的是,无法让它解决。

【讨论】:

抱歉,我认为我的问题不够清楚。必须在任何地方放置禁用警告命令对我来说不是一个可接受的解决方案,我希望 ReSharper 找到一些方法来解决它。 ForEach 示例表明至少存在一些异常。 我认为您的更新应该是评论(您正在回复我的评论)。将其关闭与禁用相同(实际上,更糟糕)。同样,ReSharper 以某种方式将ForEach 排除在外这一事实表明,某个地方的某个人已经考虑或解决了这个问题,而不涉及在本地关闭东西。 @Patrick 是的,我明白,没有设置或我不知道。也许您应该在 resharper 论坛上提问并从开发人员那里获得更简洁的答案

以上是关于在直接调用委托的情况下如何减轻“访问修改的闭包”的主要内容,如果未能解决你的问题,请参考以下文章

如何升级到 C# 5.0?访问修改后的闭包

c#中断异步操作

将委托分配给类的实例

如何在没有 StoryBoard 的两个 ViewController 之间使用委托?

设计模式之代理模式(Proxy)

如何在没有委托的情况下处理 UITextField 值更改? [关闭]