Объясните события ASP.NET

Смотрите также:

понимание событий и обработчиков событий в C#

Как веб-разработчик, мне обычно не приходится создавать собственные события для объектов, поскольку большинство из них встроено в страницу. Однако сейчас я занимаюсь довольно сложным (веб-) проектом, где, думаю, мне, возможно, придется их использовать. Я только что прочитал главу из Pro VB 2008 и платформы .NET 3.5, посвященную событиям. , делегаты и лямбда-выражения (глава 11), и хотя я лучше понимаю, что происходит, мне все еще трудно понять, когда их использовать и как использовать их. Я понимаю их реализацию, но пример в книге немного надуманный.

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

Для моего реального приложения я пытаюсь использовать событие, которое позволит мне узнать, когда элемент (некоторый класс с именем OrderItem) был обновлен, и выполнить действия в зависимости от того, был ли он обновлен. Я рассматривал возможность использования свойства флага/логического значения, но знаю, что это не совсем правильно, и давно пора научиться правильно использовать события.

Большое спасибо!

РЕДАКТИРОВАТЬ Хорошо, поэтому я хочу немного пояснить, какой смысл вызывать событие, когда все, что оно делает, это вызывает метод? Почему бы просто не вызвать метод? Это также не дубликат, поскольку я говорю концептуально, и она хочет знать конкретно об обработчиках. Кроме того, я хочу знать, в чем разница между использованием события или свойства флага. И что люди подразумевают под подпиской на событие?


person Jason    schedule 25.08.2009    source источник
comment
Уже есть несколько хороших ответов, посвященных этому.   -  person Rex M    schedule 25.08.2009
comment
Ответ Рекса в № 803242 почти дословно соответствует тому, что я бы опубликовал. Начните там, и если у вас есть какие-либо вопросы, сделайте репост.   -  person JMP    schedule 25.08.2009
comment
Не закрывайте это как обман. Есть несколько различий: 1. ОП спрашивает не как, а когда использовать событие, и 2. ОП спрашивает, подходит ли событие для их текущего проекта.   -  person Rob Allen    schedule 25.08.2009


Ответы (2)


События — это частный случай шаблона инверсия управления (IoC). Традиционный поток управления: вызывающая сторона вызывает метод у вызываемой стороны (как вы предлагаете). С помощью IoC (и, следовательно, событий) мы меняем управление приложением и вместо того, чтобы говорить вызываемому объекту, что делать, мы говорим вызываемому объекту уведомлять нас, когда происходит что-то, что нас интересует.

Рассмотрим случай с таймером. Я хочу получать уведомления каждые 5 секунд (скажем). Я не хочу постоянно опрашивать таймер ("уже пора? уже пора? уже пора?"). Вместо этого я хочу инвертировать управление потоком моего приложения. Я хочу сказать таймеру: «Когда придет время, сообщите мне, вызвав этот метод». Таким образом, управление «инвертируется», вызываемый вызывает метод у вызывающего!

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

using System;
using System.Timers;

namespace TestTimer
{
    class Program
    {
        static void Main(string[] args)
        {
            // create my timer.
            var t = new System.Timers.Timer(1000);

            // register for notification
            // tell the timer, "when it's time, call TimerGoesOff method"
            t.Elapsed += new ElapsedEventHandler( TimerGoesOff );

            // start the timer
            t.Start();

            // wait
            Console.ReadLine();
        }

        // this gets called when the timer goes off
        public static void TimerGoesOff(object source, ElapsedEventArgs e)
        {
            Console.WriteLine("The Time is " + e.SignalTime);
        }
    }
}

Вместо того, чтобы вызывать метод таймера, чтобы спросить, когда он снова сработает (как вы предлагаете), я говорю ему: «когда вы сработаете, вызовите метод TimerGoesOff». Теперь, вместо того, чтобы просто ждать, пока сработает таймер, я мог немного поработать. Рассмотрим этот код...

using System;
using System.Threading;
using System.Timers;

namespace TestTimer
{
    class Program
    {
        static void Main(string[] args)
        {
            // create my timer.
            var t = new System.Timers.Timer(1000);

            // register for notification
            t.Elapsed += new ElapsedEventHandler( TimerGoesOff );

            // start the timer
            t.Start();

            // do some work while timer is going
            new Thread(() => DoWork()).Start();

            Console.ReadLine();
        }

        // this gets called when the timer goes off
        public static void TimerGoesOff(object source, ElapsedEventArgs e)
        {
            Console.WriteLine("The Time is " + e.SignalTime);
        }

        public static void DoWork()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine( "Working ..." );
                Thread.Sleep( 1000 );
            }
        }
    }
}

Теперь я получаю вывод что-то вроде...

Working ...
The Time is 8/25/2009 1:05:59 PM
Working ...
Working ...
The Time is 8/25/2009 1:06:00 PM
Working ...
The Time is 8/25/2009 1:06:01 PM
Working ...
The Time is 8/25/2009 1:06:02 PM
The Time is 8/25/2009 1:06:03 PM

Я использовал событие Timer.Elapsed. чтобы изменить поток управления моего приложения. Я могу уйти и работать, «ожидая» пульсации события таймера. Это стало возможным благодаря IoC и Events.

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

person JP Alioto    schedule 25.08.2009
comment
это интересный и полезный ответ... хотя в VB lambdas должны возвращать значения:\ - person Jason; 26.08.2009

Допустим, у вас есть лифтовая система, и часть, которая движется вверх и вниз, называется ElevatorCar. Когда человек нажимает кнопку, чтобы подняться на 5-й этаж, ElevatorController имеет смысл вызвать метод ElevatorCar.RequestToFloor(5). Теперь, когда машина действительно прибывает на 5-й этаж, имеет смысл вызвать событие типа ArrivedAtFloor, передав 5 в качестве аргумента. Класс ElevatorController подпишется на событие ArrivedAtFloor класса ElevatorCar.

Это все потому, что класс ElevatorCar ничего не "знает" о классе ElevatorController, но класс ElevatorController знает о классе ElevatorCar. Поэтому класс ElevatorCar получает инструкции с помощью методов и уведомляет внешний мир о том, что происходит, с помощью событий.

Имеет ли это смысл?

РЕДАКТИРОВАТЬ:

Хорошо, во-первых, прочитайте отличный ответ, указанный в ссылке «Смотрите также» (предположим, что вы это сделали). Событие — это, по сути, объект, говорящий: «Если вы хотите, чтобы я звонил вам всякий раз, когда происходит X, зарегистрируйте свой метод здесь». Регистрация обработчика события с событием является «подпиской». Это позволяет инкапсулировать. Таким образом, вы можете написать, например, свой класс ElevatorCar один раз и использовать его много раз во многих других классах.

Что касается разницы между использованием события и простым вызовом метода, вы должны спросить себя, должен ли ElevatorCar знать о классе ElevatorController. Если ElevatorController вызывает ElevatorCar.GoToFloor(x), как класс ElevatorCar может «перезвонить» ElevatorController без сохранения ссылки на ElevatorController? Это означает, что вызов должен стать ElevatorCar.GoToFloor(int floor, ElevatorController ctrlr). Затем класс ElevatorCar в конечном итоге должен вызвать ctrlr.ArrivedAtFloor(floor). Но вы сталкиваетесь с множеством сложностей... что, если у вас больше одной машины? Вероятно, вам придется вызвать ctrlr.ArrivedAtFloor(floor, this). Передавать ссылки на себя не оптимально.

Что касается простой установки свойства, как другой класс узнает, что нужно прийти и прочитать свойство? Единственный способ — опрашивать свойство снова и снова, чтобы проверить его изменение. Вы, конечно, можете решить эту проблему, внедрив INotifyPropertyChanged, но опять же вы возвращаетесь к событиям!

person Scott Whitlock    schedule 25.08.2009
comment
чем это отличается от того, что класс вызывает метод вместо того, чтобы проходить через проводку события? - person Jason; 25.08.2009