Передача действия в качестве аргумента не позволяет подписаться на него - PullRequest
0 голосов
/ 30 января 2019

Вот класс теста:

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» не печатается, поскольку лямбда, подписанная на действие, не вызывается.

Мне кажется, что когдаПередавая Action в качестве аргумента, он передается по значению (в терминах C ++), поэтому вызов оператора + = происходит в другом экземпляре Action.

Как передать Action в качестве параметра, такогочто позже я могу подписаться на него с помощью оператора + =.Или, может быть, использование Actions не подходит для этой цели?

1 Ответ

0 голосов
/ 30 января 2019

Причина в том, что когда компилятор видит оператор += с делегатом, он использует метод Delegate.Combine для объединения списков вызовов делегатов, и это возвращает новый делегат.

Вы можете проверить это, если вы вызываете Console.WriteLine(action.GetHashCode()); до и после += оператора

Таким образом, вы на самом деле пытаетесь изменить переменную из external scope, присваивая новое значение переменнойв inner scope (переменная в методе).

Объяснение:

Когда мы передаем делегату Action в качестве параметра, он создает переменную в методе и помещает ссылкуэтому делегату в это.Позже, когда мы вызываем оператор +=, он возвращает новую ссылку и присваивает ее той же переменной области действия метода.В этот момент он указывает на другой объект , в то время как исходная переменная _action все еще указывает на исходный объект.

Если вы хотите присвоить новое значение для переменной, созданной вне области действия методаи чтобы изменить его указатель, вы можете передать его по ссылке, используя ключевое слово ref.Это будет указывать компилятору, что аргумент передается по ссылке, а не по значению:

private static void Subscribe(ref Action action)
{
    action += () => { Console.WriteLine("2"); };
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...