События C # и методы класса - PullRequest
6 голосов
/ 15 ноября 2011

Мне интересно, если я сделаю что-то вроде этого:

class A
{
    public MethodA()
    {
    }
    public MethodB()
    {
        ExternalObject.Click += this.MethodA;
    }
    public MethodC()
    {
        ExternalObject.Click -= this.MethodA;
    }
}

A a = new A();
a.MethodB();
a.MethodC();

Это сработает?Под «работой» я имею в виду - будет ли MethodA отписываться от события ExternalObject.Click?

И других связанных с этим вопросов:

Что происходит за кулисами, когда метод экземпляра используется вместо экземпляра делегата?(как выше)

Это вызывает неявное создание делегата?

Как оператор -= выполняет сравнение между делегатами - по ссылке или, может быть, происходит что-то более сложное?

Ответы [ 2 ]

8 голосов
/ 15 ноября 2011

Да, это будет работать так, как вы хотите.

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

Другими словами, это будет прекрасно работать:

var delegate1 = new ExternalObjectClickEventHandler(MethodA);
var delegate2 = new ExternalObjectClickEventHandler(MethodA);
ExternalObject.Click += delegate1;
ExternalObject.Click -= delegate2;

Анонимные методы отличаются, но вы не можете сделать это:

public MethodB()
{
    ExternalObject.Click += () => { return 10; };
}

public MethodC()
{
    ExternalObject.Click -= () => { return 10; };
}

Хотя методы содержат один и тот же код, они считаются разными, и поэтому это не будет работать, то есть MethodC не отменит подписку, добавленную вами в MethodB.

Чтобы решить эту проблему, вы должны хранить делегат между вызовами, например:

private ExternalObjectClickEventHandler _ClickEventHandler;
public MethodB()
{
    _ClickEventHandler = () => { return 10; };
    ExternalObject.Click += _ClickEventHandler;
}

public MethodC()
{
    ExternalObject.Click -= _ClickEventHandler;
}

Но код, который вы показали, будет работать.

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

ExternalObject.Click += MethodA;
ExternalObject.Click += new ExternalObjectClickEventHandler(MethodA);

Второй код - это то, что генерируется из первого (при условии, что тип события соответствует показанному.)

Первый синтаксис (в какой-то момент) был добавлен как «синтаксический сахар», который переводится компилятором, как будто вы написали второй синтаксис. Обратите внимание, что это происходит только в том случае, если скомпилированный может определить правильный тип 100%. Я видел несколько случаев (которые сейчас не помню), когда вам приходилось использовать полный синтаксис, потому что компилятор не мог понять, что вы имели в виду. В частности, перегрузки методов и обобщенные значения могут запутать это в этом отношении.

3 голосов
/ 15 ноября 2011

Да, MethodA будет отменено.

По поводу второго вопроса я не уверен на 100%, но думаю, = this.MethodA преобразуется в делегата в фоновом режиме.

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