如何通过引用传递 System.Action?

How to pass a System.Action by reference?

我将 System.Action 作为参数传递给一个方法,该方法执行一些冗长的操作并想向调用列表添加更多内容 Action 已通过:

class Class1
{
    private System.Action onDoneCallback;
    void StartAsyncOperation(System.Action onDoneCallback)
    {
        this.onDoneCallback = onDoneCallback;
        // do lengthy stuff

    }

    void MuchLater()
    {
         this.onDoneCallBack?.Invoke();
    }
}

class Class2
{
    public System.Action action;

    void DoStuff()
    {
        action += () => print ("a");
        new Class1().StartAsyncOperation(action);
    }

    {
        // ... much later in another place but still before StartAsyncOperation ends
        action += () => print ("b");
    }
}

但是,只有在将 Action 作为参数传递之前用 += 添加的内容才会被调用。因此,在此示例中,它只会打印 "a" 而不会打印 "b".

这让我觉得 System.Action 在作为参数传递时被 复制了 (就像原始类型,例如 int 会)。所以,后面做+=的时候,对SomeAsyncOperation里面的本地副本action没有影响。

我想通过 System.Actionref。但是,我需要将它作为成员变量存储在 Class1 中,我不能将成员变量设为 ref!

所以,基本上,问题是:在回调已经通过并且冗长的操作很长但尚未结束之后,如何向回调的调用列表添加更多内容。

编辑:

结束替换

new Class1().StartAsyncOperation(action);

new Class1().StartAsyncOperation(() => action?.Invoke());

一个选项:

class Class2
{
    public List<System.Action> callbacks = new List<System.Action>();

    void DoStuff()
    {

        callbacks.Add(() => print("a"));
        new Class1().StartAsyncOperation(() => {
            forach(var a in callbacks()
            {
                a();
            }
        });
    }

    {
        // ... much later in another place but still before StartAsyncOperation ends
        callbacks.Add(() => print ("b"));
    }
}

您将关闭列表,因此任何更改在回调 运行 时仍然可用。

委托类型是不可变的引用类型,如字符串:

s += "\n";

s 现在是对不同对象的引用。如果将它传递给一个方法,该方法将获得对该对象的引用,而不是 s 下一个可能引用的任何对象。此 lambda returns,并将继续 return,调用 lambda 时 s 所指的任何对象:

() => s;

这同样适用于 a += () => {};a 之后引用不同的对象,但是您可以创建一个 lambda 来执行 a 的当前值,无论它是什么。

因此:

new Class1().StartAsyncOperation(() => action());

无论您在那之后做什么 action,您传入的 lambda 都会引用 action 的当前值。

在家试试:

Action a = () => Console.Write("a");

//  This would print "a" when we call b() at the end
//Action b = a;

//  This prints "a+" when we call b() at the end.
Action b = () => a();

a += () => Console.Write("+");

b();