Разница между + = и Delegate.Combine - PullRequest
5 голосов
/ 11 апреля 2019

Я создал систему событий, которая поддерживает dictionary делегатов, добавляет / удаляет элементы к этому dictionary с помощью общих методов подписки / отмены подписки (каждый из которых выполняет действие type T) и имеет Метод публикации, чтобы уведомить подписчиков, когда что-то происходит (который также принимает действие типа T). Все работает нормально, но я заметил, что не могу использовать + = или - = при добавлении или удалении элементов к моему dictionary, так как типы, передаваемые в методы (Action of T), не соответствуют типам, хранящимся в dictionary (Delegate). Следующий фрагмент показывает, что я могу и не могу сделать.

private readonly Dictionary<Type, Delegate> delegates = new Dictionary<Type, Delegate>();

public void Subscribe<T>(Action<T> del)
{
    if (delegates.ContainsKey(typeof(T)))
    {
        // This doesn't work!
        delegates[typeof(T)] += del as Delegate;
        // This doesn't work!
        delegates[typeof(T)] += del;
        // This is ok
        delegates[typeof(T)] = (Action<T>)delegates[typeof(T)] + del;
        // This is ok
        var newDel = (Action<T>)delegates[typeof(T)] + del;
        delegates[typeof(T)] = newDel;
        // This is ok
        del += (Action<T>)delegates[typeof(T)];
        delegates[typeof(T)] = del;
        // This is ok
        delegates[typeof(T)] = Delegate.Combine(delegates[typeof(T)], del);
    }
    else
    {
        delegates[typeof(T)] = del;
    }
}

Я в основном понимаю ответ Джона Скита здесь + = оператор для делегата , в частности, эта часть

Бинарный оператор + выполняет комбинацию делегатов, когда оба операнда имеют некоторый тип делегата D. (Если операнды имеют разные типы делегатов, возникает ошибка времени привязки.)

Что я не понимаю, это

Компилятор превращает его в вызов Delegate.Combine. Обратная операция с использованием - или - =, использует Delegate.Remove.

Что именно происходит, когда я использую + = или - =, вместо Delegate.Combine? Каковы различия между ними, делающими одну реализацию допустимой, а другую недействительной?

1 Ответ

5 голосов
/ 11 апреля 2019

В конце ответа, который вы связали, написано:

Поскольку System.Delegate не является типом делегата, для него не определен оператор +.

Это объясняет, почему это не работает (оба операнда Delegate):

delegates[typeof(T)] += del as Delegate;

Delegate.Combine работает, потому что объявлено так :

public static Delegate Combine (params Delegate[] delegates);

Обратите внимание, как он принимает параметры типа Delegate вместо определенного типа делегата. И он выдаст ArgumentException, если делегаты не одного типа.

Таким образом, компилятор не только меняет оператор + на Delegate.Combine, но также выполняет некоторую проверку типов! С другой стороны, проверка типа во время компиляции не выполняется, если вы используете Delegate.Combine напрямую. Delegate.Combine проверяет только типы во время выполнения.

Все остальные строки работают, потому что вы приводите, то есть сообщаете компилятору, к какому типу относятся делегаты, делая оба операнда + типа Action<T>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...