Как запустить метод после определенного интервала времени?

Понятно: например, представьте себе кнопку в моей форме. Когда пользователь нажимает на кнопку, некоторый метод void должен запускаться через 30 секунд.

Был бы пустой метод DoAfterDelay который принимает два входных параметра. Первый метод - это метод (с использованием делегатов), а второй - временной интервал. Итак, я буду иметь:

public delegate void IVoidDelegate();
static void DoAfterDelay(IVoidDelegate TheMethod, TimeSpan Interval)
    {
        // *** Some code that will pause the process for "Interval".
        TheMethod();
    }

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

System.Threading.Thread.Sleep(Interval);

Но этот код мне не подходит, потому что он останавливает весь процесс и останавливает программу. Я не хочу, чтобы программа застряла в методе DoAfterDelay. Вот почему Thread.Sleep бесполезен.

Так кто-нибудь может предложить лучший способ? Конечно, я искал об этом, но большинство решений, которые я нашел, были основаны на использовании таймера (как здесь, например). Но использование таймера - мое последнее мнение, потому что метод должен запускаться один раз, а использование таймеров делает программу непонятной для чтения. Поэтому я ищу лучшее решение, если оно есть. Или, может быть, я должен использовать таймеры?

Я думаю, что я должен играть с темами, но не уверен. Поэтому мне интересно, если кто-нибудь может привести меня к решению. Заранее спасибо.

Ответ 1

Можете ли вы использовать задачу?

    Task.Factory.StartNew(() =>
    {
        System.Threading.Thread.Sleep(Interval);
        TheMethod();
    });

Ответ 2

Здесь вы можете использовать функцию async для ожидания .Net 4.5

Вы можете использовать Task.Delay и дать задержку в милисекундах. Это очень чистый способ. например:

    private async void button1_Click(object sender, EventArgs e)
    {
        await Task.Delay(5000);

        TheMethod();
    }

Ответ 3

DoAfterDelay запускает таймер, который запускается только один раз, когда он истекает, он вызывает вашу функцию "TheMethod". Почему это было бы грязно?

Ответ 4

Вот что вы хотите:

    public static void Example1c()
    {
        Action action = DoSomethingCool;
        TimeSpan span = new TimeSpan(0, 0, 0, 5);

        ThreadStart start = delegate { RunAfterTimespan(action, span); };
        Thread t4 = new Thread(start);
        t4.Start();

        MessageBox.Show("Thread has been launched");
    }
    public static void RunAfterTimespan(Action action, TimeSpan span)
    {
        Thread.Sleep(span);
        action();
    }
    private static void DoSomethingCool()
    {
        MessageBox.Show("I'm doing something cool");
    }

Одним из преимуществ использования Action является то, что его можно легко изменить, чтобы передать параметры. Предположим, вы хотите передать целое число в DoSomethingCool. Просто измените так:

    public static void Example1c()
    {
        Action<int> action = DoSomethingCool;
        TimeSpan span = new TimeSpan(0, 0, 0, 5);
        int number = 10;

        ThreadStart start = delegate { RunAfterTimespan(action, span, number); };
        Thread t4 = new Thread(start);
        t4.Start();

        MessageBox.Show("Thread has been launched");
    }
    public static void RunAfterTimespan(Action<int> action, TimeSpan span, int number)
    {
        Thread.Sleep(span);
        action(number);
    }
    private static void DoSomethingCool(int number)
    {
        MessageBox.Show("I'm doing something cool");
    }

Очень гибкий...

Ответ 5

Существует несколько способов создания потоков, но, конечно, это зависит от того, что вы делаете. Вы можете создать поток на лету, как это:

Thread aNewThread = new Thread(
    () => OnGoingFunction()
);
aNewThread.Start();

Этот поток будет работать в фоновом режиме. Функция, которую вы хотите сделать, должна иметь метод сна для сна, когда выполняется ее обработка. Так что-то вроде этого:

private void OnGoingFunction()
{
   //Code....
   Thread.Sleep(100); //100 ms, this is in the thead so it will not stop your winForm
   //More code....
}

Я надеюсь, что это поможет.

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

Ответ 6

Вы должны создать Coroutine

public IEnumerator waitAndRun()
{
    // WAIT FOR 3 SEC
    yield return new WaitForSeconds(3);
    // RUN YOUR CODE HERE ...
}

И назовите его с помощью:

StartCoroutine(waitAndRun());

Ответ 7

Вы можете указать точные секунды, используя

DateTime runTime = new DateTime();
double waitSeconds = (runTime - DateTime.Now).TotalSeconds;

Task.Factory.StartNew(() =>
{
    Thread.Sleep(TimeSpan.FromSeconds(waitSeconds));
    YourMethod();
});

runTime => Когда вы хотите выполнить метод.