обработчик событий c # добавляется дважды

Это вымышленный пример, но я не мог понять, что произойдет, если функция InitialiseTimer будет вызвана дважды. Срабатывает ли функция истекшего таймера дважды. Изменится ли это, если функции сделать статическими?

    private static void InitialiseTimer()
    {
            TheTimer = new System.Timers.Timer();
            TheTimer.Interval = 400;
            TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
            TheTimer.AutoReset = false;
    }   

    public void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        //Do stuff in here
    }

Я собирался использовать ниже, чтобы предотвратить это

Был ли уже добавлен обработчик событий?

Спасибо, Ричард


person probably at the beach    schedule 03.03.2011    source источник


Ответы (5)


Я думаю, что следующий сценарий демонстрирует сценарий и действительно запускается дважды, а также предлагаю простое изменение (закомментированный код) для метода Init, который должен исправить поведение. (Не потокобезопасный, кстати, потребуются дополнительные блокировки)

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var counter = 0;
        var ts = new ThreadStart(() =>
            {

                Foo.Fired += (o, e) =>
                    {
                        counter++;
                    };
                Foo.InitialiseTimer();
                Foo.InitialiseTimer();
            });
        var t = new Thread(ts);
        t.Start();

        Thread.Sleep(30);
        Assert.AreEqual(1, counter);
    }
}

public class Foo
{
    private static System.Timers.Timer TheTimer = null;

    public static event EventHandler Fired;

    public static void InitialiseTimer()
    {
        //if (TheTimer != null)
        //{
        //    TheTimer.Stop();
        //    TheTimer = null;
        //}
        TheTimer = new System.Timers.Timer();
        TheTimer.Interval = 10;
        TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
        TheTimer.AutoReset = false;
        TheTimer.Start();
    }

    public static void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        //Do stuff in here
        if (Fired != null)
        {
            Fired(null, null);
        }
    }
}
person Perry    schedule 03.03.2011

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

Это не изменится, если вы сделаете TheTimer_Elapsed статическим, потому что вы по-прежнему будете содержать две ссылки на этот статический метод.

В большинстве случаев нет необходимости писать сложные вещи, подобные тому, что Блер Конрад опубликовал в вопросе, на который вы ссылались. Только не забывайте использовать -= каждый раз, когда у вас есть +=, и вы будете в безопасности.

person Ilya Kogan    schedule 03.03.2011

если вы вызовете метод InitialiseTimer дважды, вы создадите два таймера, к каждому из них будет прикреплен только один обработчик событий, но они могут пройти оба. На самом деле речь идет не о том, чтобы метод был статическим или нет, это больше о самом методе, вы можете проверить, имеет ли TheTimer значение null, а все остальное сделать только в том случае, если оно равно null, поэтому вы назначаете его только один раз.

person Davide Piras    schedule 03.03.2011

Если событие зарегистрировано дважды, у вас будет два казни.

Вы можете проверить, является ли событие нулевым, и проблема будет решена.

person buda    schedule 03.03.2011
comment
Как это решает проверка на null? Что, если для этого события были зарегистрированы другие обработчики? - person Ilya Kogan; 03.03.2011
comment
Это будет проверка на ноль для вновь созданного экземпляра Timer, а не для того, который был создан в предыдущем вызове, так что на самом деле это ничего не решает. Однако установка на нуль поля TheTimer решит проблему. - person Fredrik Mörk; 03.03.2011
comment
Конечно, я подумал, что вам нужно будет проверить, является ли событие нулевым на том же таймере, а не на вновь созданном. - person buda; 03.03.2011

Статический или нет, вы воссоздаете таймер. Таким образом, вы можете вызывать InitialiseTimer много-много раз, не добавляя более одного обработчика. Однако у вас будет много таймеров ...

person Emond Erno    schedule 03.03.2011