这是测试班:
public class TestClass
{
private readonly Action _action;
public TestClass()
{
_action += () => { Console.WriteLine("1"); };
Subscribe(_action);
_action?.Invoke();
}
private static void Subscribe(Action action)
{
action += () => { Console.WriteLine("2"); };
}
}
在运行时,不会打印“ 2”,因为不会调用订阅该动作的lambda。
在我看来,当将Action作为参数传递时,它是按值传递的(使用C ++术语),因此对+ =运算符的调用发生在Action的另一个实例上。
如何传递Action作为参数,以便以后可以使用+ =运算符订阅它。还是为此目的使用操作无效?
答案 0 :(得分:2)
原因是,当编译器看到带有委托的+=
运算符时,它使用Delegate.Combine
方法来连接委托的调用列表,并返回 new 委托。 / p>
可以检查是否在Console.WriteLine(action.GetHashCode());
运算符之前和之后调用+=
因此,您实际上是通过为 inner 范围内的变量(方法范围内的变量)分配新值来尝试从 outer 范围内更改变量。
说明:
当我们将Action
委托作为参数传递时,它将创建一个方法范围的变量,并将对该委托的引用放入其中。稍后,当我们调用+=
运算符时,它将返回一个新引用,并将其分配给相同的方法作用域变量。此时,它指向另一个对象,而原始_action
变量仍指向初始对象。
如果要为在方法范围之外创建的变量分配新值并更改其指针,可以使用ref
关键字通过引用传递它。这将向编译器指示参数是通过引用而不是通过值传递的:
private static void Subscribe(ref Action action)
{
action += () => { Console.WriteLine("2"); };
}