访问修改后的闭包:ReSharper

Access to modified closure: ReSharper

我创建了一个处理数据库访问的库。我最近添加了事务处理;但是,我遇到了一个小问题。为了概述这一点,我为了演示目的编写了这个示例:

class Program
{
    static void Main(string[] args)
    {
        String data = null;
        DoAction(ref data, () =>
        {
            Console.WriteLine(data);
        });
        Console.ReadLine();
    }

    private static void DoAction(ref String data, Action action)
    {
        if (data == null)
            data = "Initialized Data";
        action();
    }
}

我在 'data' 变量的以下代码行上得到 "Access to modified closure" 下划线:

Console.WriteLine(data);

我知道修改 ref 数据变量可能会导致问题(例如,当 运行 foreach 循环时)。但是,在以下情况下,我认为不会发生这种情况。

这是另一个版本,其中循环进一步更改变量 - 输出符合预期:

class Program
{
    static void Main(string[] args)
    {
        String data = null;
        for (var i = 0; i < 10; i++)
            DoAction(ref data, () =>
            {
                Console.WriteLine(data);
            });
        Console.ReadLine();
    }

    private static void DoAction(ref String data, Action action)
    {
        if (data == null)
            data = "Initialized Data";
        else
            data += "|";

        action();
    }
}

ReSharper 让我创建一个局部变量,但我明确想使用从 DoAction() 方法创建的字符串。如果我接受 ReSharpers 方法,它实际上会破坏代码。还有其他方法可以解决这个问题吗?我想使用这种 Action 方法,但我也不希望 ReSharper 抱怨它(并且可能不禁用 ReSharpers 检查)。

有什么建议吗?

我建议首先避免为此使用 ref 参数 - 这对我来说似乎不必要地复杂。我将 DoAction 重写为:

static string DoAction(string data, Action<string> action)
{
    data = data == null ? "Initialized Data" : data + "|";
    action(data);
    return data;
}

那么你可以拥有:

data = DoAction(data, Console.WriteLine);

或者如果您想使用 lambda 表达式:

data = DoAction(data, txt => Console.WriteLine(txt));

如果您之后实际上不需要结果,您可以将 DoAction 设为 void 方法。 (不清楚为什么您需要返回结果 一个在 DoAction 中执行的委托,但大概这在更广泛的上下文中更有意义。)

如果您确定该警告不合适,则 InstantHandleAttribute 记录为:

Tells code analysis engine if the parameter is completely handled when the invoked method is on stack. If the parameter is a delegate, indicates that delegate is executed while the method is executed. If the parameter is an enumerable, indicates that it is enumerated while the method is executed.

我想这正是你想要的。

您可以从 JetBrains.Annotations 包中获取属性,或者从 ReSharper 选项中复制粘贴。