Указание объекту таймера асинхронно вызывать событие «Истек» - PullRequest
3 голосов
/ 30 августа 2010

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

Я пробовал следующее:

int originalInterval = t.Interval;
t.Interval = 0;
t.Interval = originalInterval;

но это не было согласовано.

Я создал новый таймер, унаследованный от System.Timers.Timer, и раскрыл метод «Tick», но проблема заключалась в том, что событие «Elapsed» затем запускалось синхронно.

Когда я реализовал «Тик» с новым потоком - результаты, опять же, были непоследовательными.

Есть ли лучший способ реализовать это?

Ответы [ 3 ]

4 голосов
/ 30 августа 2010

Однажды у меня возникла та же проблема, поэтому я использовал AutoResetEvent, чтобы узнать, был ли успешно запущен Elapsed:

/// <summary>
/// Tickable timer, allows you to manually raise a 'Tick' (asynchronously, of course)
/// </summary>
public class TickableTimer : System.Timers.Timer
{
    public new event ElapsedEventHandler Elapsed;

    private System.Threading.AutoResetEvent m_autoResetEvent = new System.Threading.AutoResetEvent(true);

    public TickableTimer()
        : this(100)
    {
    }

    public TickableTimer(double interval)
        : base(interval)
    {
        base.Elapsed += new ElapsedEventHandler(TickableTimer_Elapsed);
    }

    public void Tick()
    {
        new System.Threading.Thread(delegate(object sender)
        {
            Dictionary<string, object> args = new Dictionary<string, object>
            {
                {"signalTime", DateTime.Now},
            };
            TickableTimer_Elapsed(this, Mock.Create<ElapsedEventArgs>(args));
        }).Start();
        this.m_autoResetEvent.WaitOne();
    }

    void TickableTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        m_autoResetEvent.Set();
        if (this.Elapsed != null)
            this.Elapsed(sender, e);
    }
}
3 голосов
/ 30 августа 2010

Такое ощущение, что вы должны немного взглянуть на свой дизайн.Обычно я стараюсь избегать, чтобы метод обработчика событий содержал фактическую выполняемую работу, но я скорее стараюсь, чтобы он был просто триггером, вызывая какой-то другой метод, выполняющий эту работу.Таким образом, вы также можете вызывать этот другой метод из любого другого места:

private void Timer_Tick(object sender, EventArgs e)
{
    new Thread(MethodThatDoesTheWork).Start();
}

private void MethodThatDoesTheWork()
{
    // actual work goes here
}

Теперь вы можете вызывать MethodThatDoesTheWork из любого места в классе (синхронно или асинхронно, используя отдельный поток).

В качестве альтернативы, если MethodThatDoesTheWork должен всегда быть асинхронным вызовом, вы можете создать поток внутри этого метода:

private void MethodThatDoesTheWork()
{
    new Thread(() =>
    {
         // work code goes here
    }).Start();
}

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

0 голосов
/ 30 августа 2010

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

Вы не указали никаких подробностей относительно того, чтоВы имеете в виду «не соответствует».Обычно должно работать следующее:

Thread thread = new Thread(myDelegate);
thread.Start();

Конечно, myDelegate может быть лямбда-выражением, если вам нужно передать параметры:

Thread thread = new Thread(() => myMethod(param1, param2));
thread.Start();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...