2009-10-29 4 views
12

Возможно ли в C# подключить одно событие к другому, так что излучающее первое событие будет издавать второе? Единственный способ, который я вижу, - создать функцию заглушки, которая выдает второе событие и связывает первое событие с этой функцией. Компилятор не хотите подключить событие к событию или события к функции Anonymouse/лямбда, что вызывает еще одно событие:Подписаться на событие в C#?

class Ui { public event EventHandler OnClick; } 
class Logic { public event EventHandler OnExit; } 
var ui = new Ui(); 
var logic = new Logic(); 
ui.OnClick += logic.OnExit; // Not working. 
ui.OnClick += (a, b) => logic.OnExit; // Not working either :(. 

Может быть, это какой-то декоратор или некоторые черной магии, которая позволяет цепи событий без функций окурка?

ответ

9

Вы не можете сделать это, потому что вы вообще ничего не может сделать, чтобы события из-за пределов объекта, которому принадлежит это добавление и удаление обработчиков, за исключением. В частности, вы не можете перечислить существующих зарегистрированных обработчиков, и вы не можете их поднять. В вашем случае «копирование» события по сути является тем же самым, что и маскировка, и позволит вам обойти это ограничение; поэтому это запрещено.

См. this recent answer, чтобы получить более подробное объяснение, почему все так, как они есть. Мне просто не хочется переписывать все это здесь.

Для вашего конкретного случая, если у вас есть оба класса, обходной путь, чтобы сделать их сотрудничество конкретно - сделать Ui быть в курсе соответствующей Logic например, и добавить обработчик событий Logic.OnClick в Ui.OnClick.add реализации. Конечно, это вводит сцепление; вы можете уменьшить его до некоторой степени, используя более общие интерфейсы, но вы не можете полностью избавиться от него.

В качестве примечания стороны OnClick не является хорошим именем для события .NET. Общее руководство по именованию говорит, что должно быть просто ClickOnClick должно быть именем метода protected virtual, который его повышает).

+2

. Введем связь - это говорит, что все это^_ ^. – grigoryvp

+0

Это точно. Список обработчиков является частным для объекта, которому принадлежит событие, по дизайну. Причина в том, что только объект должен контролировать, когда и как вызываются обработчики. Это базовое инкапсулирование. Если вы хотите сломать инкапсуляцию, вам нужно предоставить специальный штрих для этого, и ваши классы должны знать об этом - следовательно, соединение. То, о чем вы просите, действительно ничем не отличается от «можно ли получить доступ к частной области одного из моих классов из другого?». –

+0

Так что в основном все, что мне нужно сделать, это переместить код подписки в класс, которому принадлежит второе событие? :) – grigoryvp

3

Вы можете сделать это, спрятав основное событие для логики, а затем контролируя вызовы Add/Remove, для которых требуется параметр пользовательского интерфейса.

public class UI { 
    public EventHandler OnClick; 
} 
public class Logic { 
    private event EventHandler _onExit; 
    public void AddOnExit(UI ui, EventHandler e) { 
    ui.OnClick += e; 
    _onExit += e; 
    } 
    public void RemoveOnExit(UI ui, EventHandler e) { 
    ui.OnClick -= e; 
    _onExit -= e; 
    } 
} 
+1

В своем примере он не пытается связать два события одного и того же объекта - он пытается связать события сопоставления пары между двумя разными объектами. –

+0

@Pavel, ах ОК. Та же логика работает, хотя между двумя объектами, если они связаны иным образом. Но да, немного отличающийся от моего примера, обманет – JaredPar

Смежные вопросы