Что происходит с событием переменной области действия метода? - PullRequest
2 голосов
/ 16 сентября 2010

Рассмотрим следующий код:

public class Bar {
    Foo foo;
    void Go() {
       foo = new Foo();
       foo.Send(...);

       foo.Dispose();
       foo = null; 
    }
}

public class Foo : IDisposable {   
    public void Send(byte[] bytes) {
        SocketAsyncEventArgs args = new SocketAsyncEventArgs();
        args.SetBuffer(bytes, 0, bytes.Length);
        args.UserToken = socket;
        args.RemoteEndPoint = endPoint;
        args.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendCompleted);

        socket.SendAsync(args);
    }

    private void OnSendCompleted(object sender, SocketAsyncEventArgs e) {
        Debug.WriteLine("great");
    }

    public void Dispose() {
       //
    }
}

Таким образом, класс Bar запускает метод Init, который создает экземпляр класса Foo и запускает метод Send, а затем уничтожает экземпляр Foo. Метод Send тем временем создает экземпляр уровня метода SocketAsyncEventArgs, устанавливает событие Completed и затем запускает метод SendAsync.

Если предположить, что SendAsync завершает работу после того, как для экземпляра Foo установлено значение null, что происходит с обработчиком событий? Это все еще огонь? Если я не хочу, чтобы он запускался, как правильно очистить класс Foo, зная, что переменная уровня метода порождает событие.

Ответы [ 2 ]

3 голосов
/ 16 сентября 2010

Да, он все еще будет стрелять.Установка переменной в null не запускает сборку мусора или что-то в этом роде.Он просто устанавливает переменную в ноль.(Важно различать переменную и экземпляр. Нет такого понятия, как «установка экземпляра на ноль». Если я записываю свой домашний адрес на листе бумаги, а затем стираю его снова, это не разрушает мойhouse.)

Звучит так, как будто вы хотите, чтобы ваш Dispose метод "помнил", что объект был очищен, а затем, если OnSendCompleted вызывается после утилизации, просто игнорируйте его.В качестве альтернативы, отследите любые «запросы в полете» и отмените их в Dispose ..., отметив, что некоторые запросы могут завершиться , в то время как вы отменяете весь лот.Обратите внимание: вместо явного вызова Dispose() вы почти всегда должны использовать оператор using, который обеспечит вызов Dispose(), однако оператор using заканчивается (например, с исключением).

1 голос
/ 16 сентября 2010

Как насчет попытки отсоединить событие с помощью - = в вашем методе OnSendCompleted?

e.Completed -= new EventHandler<SocketAsyncEventArgs>(OnSendCompleted);
...