Составление многоадресных делегатов в C# — следует ли использовать операторы или Action.Combine?

Читая документацию, я вижу, что оператор + можно использовать для составления/объединения делегатов одного типа.

Точно так же я вижу, что могу удалить a из составленного делегата, используя оператор -.

Я также заметил, что тип Action имеет статические методы Combine и Remove, которые можно использовать для объединения списков вызовов двух делегатов и для удаления последнего экземпляра списка вызовов делегата из списка вызовов другого делегата соответственно.

        Action a = () => Debug.WriteLine("Invoke a");
        Action b = () => Debug.WriteLine("Invoke b");
        a += b;
        a.Invoke(); 

        //Invoke a
        //Invoke b

        Action c = () => Debug.WriteLine("Invoke c");
        Action d = () => Debug.WriteLine("Invoke d");
        Action e = Action.Combine(c, d);
        e.Invoke();

        //Invoke c
        //Invoke d

        a -= b;
        a.Invoke();

        //Invoke a

        e = Action.Remove(e, d);
        e.Invoke(); 

        //Invoke c

Похоже, они дают одинаковые результаты с точки зрения того, как они объединяются/удаляются из списка вызовов.

Я видел оба способа, используемые в различных примерах на SO и в другом коде. Есть ли причина, по которой я должен использовать тот или иной способ? Есть ли пит-фоллы? Например, я вижу предупреждение в строке a -= b; о том, что Delegate subtraction has unpredictable results — следует ли мне избегать этого с помощью команды «Удалить»?


person Fraser    schedule 07.01.2013    source источник
comment
Obviously the static methods return a new delegate whilst the accessors don't Неправильно   -  person SLaks    schedule 07.01.2013
comment
Вычитание делегатов имеет непредсказуемые результаты — это предупреждение ReSharper, и оно кажется плохо сформулированным. Результаты вполне предсказуемы. Они определены в спецификации C#. Однако для некоторых пользователей их мысленная модель вычитания делегатов не соответствует спецификации, и поэтому результат для них непредсказуем.   -  person Mike Zboray    schedule 07.01.2013
comment
@SLaks - можете ли вы объяснить это дальше? a += b не возвращает новый Delegate, в то время как Delegate.Combine(a, b) явно возвращает.   -  person Fraser    schedule 07.01.2013
comment
@mike z - да, это немного умственно... ха...   -  person Fraser    schedule 08.01.2013
comment
@Fraser: Неправильно. a += b — это сокращение от a = a + b (как и любое другое добавление +=), которое явно возвращает нового делегата. (Обратите внимание, что события совершенно разные)   -  person SLaks    schedule 08.01.2013


Ответы (1)


Операторы-делегаты (+ и -) являются сокращением для статических методов.
Нет никакой разницы.

a += b компилируется в a = (Action)Delegate.Combine(a, b)

person SLaks    schedule 07.01.2013
comment
Большое спасибо - меня действительно озадачило то, что a += b оставляет a как тип Action, в то время как Delegate.Combine(a, b) возвращает тип Delegate, а не тип Action... - person Fraser; 07.01.2013
comment
@Fraser: Если вы посмотрите на сгенерированный IL, вы увидите инструкцию castclass после Delegate.Combine для +=. (Вы можете увидеть это в LINQPad) - person SLaks; 07.01.2013
comment
... Итак, методы доступа не возвращают тип Delegate, они возвращают объект того же типа, что и два объекта, которые составляются (в данном случае Action), а статические методы всегда возвращают Delegate. Я думаю, что запутал проблему, просто сказав «делегат», а не набрав Delegate - person Fraser; 08.01.2013
comment
@Fraser: (обратите внимание, что они называются операторами, а не средствами доступа). Операторы делают то же самое, что и методы; статические методы также возвращают тот же тип, что и их операнды. - person SLaks; 08.01.2013
comment
ах, да... меня сбило с толку то, что я использовал Delegate.Combine... а не Action.Combine. Извините за путаницу. - person Fraser; 08.01.2013