Почему я могу проверить некоторые обработчики событий на ноль, а некоторые нет? - PullRequest
2 голосов
/ 21 декабря 2010

У меня ужасный кусок кода, который добавляет обработчики событий.Проблема в том, что если код вызывается несколько раз, обработчики событий вызываются несколько раз.

Чтобы решить эту проблему, я сначала удаляю обработчик событий, а затем добавляю его.

Теперь явидел следующее поведение:

Некоторые обработчики событий могут быть проверены как:

if (object.event == null) {
    //
    // Code
    //
}

другие формы

if (object.object.event == null) {
    //
    // Code
    //
}

Я получаю сообщение типа 'объект.object.event 'может происходить только слева от - = или + =.(Поскольку я использую немецкую версию visual studio, я не знаю правильного перевода на английский).

Я понятия не имею, почему поведение выглядит таким непоследовательным, поэтому я был бы признателен за некоторую информацию оэто.

Чтобы быть более конкретным: это пользовательский контроль.

if (myControl.Event == null) {
    //
    // works
    //
}

if (myControl.TreeView.NodeMouseClick == null) {
    //
    // doesn't work
    //
}

Ответы [ 5 ]

4 голосов
/ 21 декабря 2010

Чтобы решить проблему, я сначала удаляю обработчик событий, а затем добавляю его.

Это не решает проблему.Ключевое слово event предоставляет средства доступа для объекта делегата.Так же, как собственность предоставляет средства доступа к полю.Для свойства всегда требуется один get или set .Событие имеет методы добавления, удаления и поднятия.Но компилятор создаст для них реализацию по умолчанию, если вы сами этого не сделаете.Что довольно распространено.

Преимущество метода доступа к свойству состоит в том, что вспомогательное поле может быть закрытым.Никто не может связываться с этим, кроме класса, который содержит поле.Весь доступ должен пройти через get и set accessors.Ключевое слово event работает точно так же, никто не может связываться с объектом делегата, кроме кода в классе, который содержит событие.

Что пробивает дыру в вашей попытке избежатьподнимая событие.Вы не можете связываться со списком подписчиков для события, которое объявлено в другом классе, компилятор говорит вам об этом.Обычный способ сделать это - установить флаг bool, чтобы указать, что события должны временно игнорироваться.Обработчик событий может проверить этот флаг и избежать каких-либо побочных эффектов.

3 голосов
/ 21 декабря 2010

SLaks правильно и связано с некоторыми отличными ресурсами. Вот соответствующая цитата из статьи Криса Барроуза :

Позвольте мне кратко остановиться здесь и объяснить, как работает привязка + = в C #. Есть две возможности:

  1. либо есть фактический оператор +, например, с целыми числами, и x + = y связывается с «x = x + y», за исключением того, что x вычисляется только один раз. Это составной оператор присваивания; или
  2. вещь с левой стороны - событие, и x.E + = y связывается с «x.add_E (y)». Это оператор доступа к событиям, и фактически это единственный способ привязки к средству доступа к событиям.

Так что же мы имеем в приведенном выше фрагменте? Что ж, лишняя деталь, которую вам нужно решить, - это следующее правило о полеподобных событиях в C #: вне класса или структуры, которая определяет полеподобное событие E, привязка к имени E разрешается в само событие, на котором единственной законной операцией является вызов метода доступа; внутри класса или структуры, определяющей подобное E поле событие, привязка к имени E разрешается в поле частного делегата .

В вашем случае при разрешении myControl.Event вы внутри класса myControl, поэтому вы не видите объект события; вместо этого вы видите реальный объект делегата, который вы можете сравнить с нулем. При разрешении myControl.TreeView.NodeMouseClick вы находитесь за пределами класса TreeView, поэтому вы не можете получить доступ к реальному объекту делегата; все, что вы получаете, это объект события, который нельзя сравнить с нулем.

Если я правильно понимаю, все это не помогло бы вам, так как, по-видимому, после того, как вы проверите нулевое значение, вы попытаетесь запустить событие TreeView для него, что вы не можете сделать .

В зависимости от того, что вы пытаетесь сделать, вы, вероятно, можете создать подкласс TreeView и добавить метод internal, который вызовет защищенный метод TreeView.OnNodeMouseClick для запуска события.

3 голосов
/ 21 декабря 2010

Вы можете получить доступ к полю поддержки только для события, определенного в вашем классе.
Для получения дополнительной информации см. spec . (Хотя это изменилось в C # 4, эти изменения для вас не важны)

Лучшей практикой в ​​вашем случае будет создание protected internal On<i>EventName</i> метода в каждом классе.

0 голосов
/ 21 декабря 2010

Автоматические события, как этот:

public event EventHandler SomethingHappened;

реализуются компилятором с использованием многоадресного делегата.

Когда вы пишете myControl.Event == null, компилятору действительно нужно вызвать Delegate.GetInvocationList для этого делегата. Компилятор не позволяет вам сделать это, если код не находится внутри метода класса, выставляющего событие, отсюда и ошибка (он позволяет только добавлять или удалять из списка вызовов).

Если бы мы говорили о событии, которое вы определяете в своем собственном классе, то у вас была бы возможность выставить список вызовов (например, с помощью метода) и выполнить то, что вы пытаетесь сделать. Но для существующих классов (например, TreeView) это невозможно.

0 голосов
/ 21 декабря 2010

Вы можете запрашивать только собственные обработчики событий для прикрепленных слушателей.

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