web-dev-qa-db-fra.com

Comment faire fonctionner une application console .NET?

Considérons une application console qui démarre certains services dans un thread séparé. Il suffit d’attendre que l’utilisateur appuie sur Ctrl + C pour le fermer. 

Quel est le meilleur moyen de procéder?

static ManualResetEvent _quitEvent = new ManualResetEvent(false);

static void Main() {
    Console.CancelKeyPress += (sender, eArgs) => {
        _quitEvent.Set();
        eArgs.Cancel = true;
    };

    // kick off asynchronous stuff 

    _quitEvent.WaitOne();

    // cleanup/shutdown and quit
}

Ou ceci, en utilisant Thread.Sleep (1):

static bool _quitFlag = false;

static void Main() {
    Console.CancelKeyPress += delegate {
        _quitFlag = true;
    };

    // kick off asynchronous stuff 

    while (!_quitFlag) {
        Thread.Sleep(1);
    }

    // cleanup/shutdown and quit
}
89
intoOrbit

vous voulez toujours éviter d'utiliser des boucles while, surtout lorsque vous forcez le code à revérifier les variables. Cela gaspille les ressources du processeur et ralentit votre programme.

Je dirais certainement le premier.

58
Mike

Alternativement, une solution plus simple est simplement:

Console.ReadLine();
27
Cocowalla

Vous pouvez le faire (et supprimer le gestionnaire d'événements CancelKeyPress):

while(!_quitFlag)
{
    var keyInfo = Console.ReadKey();
    _quitFlag = keyInfo.Key == ConsoleKey.C
             && keyInfo.Modifiers == ConsoleModifiers.Control;
}

Pas sûr que ce soit mieux, mais je n'aime pas l'idée d'appeler Thread.Sleep dans une boucle.

11
Thomas Levesque

Je préfère utiliser le Application.Run

static void Main(string[] args) {

   //Do your stuff here

   System.Windows.Forms.Application.Run();

   //Cleanup/Before Quit
}

des docs: 

Commence à exécuter une boucle de message d'application standard sur le thread actuel, sans formulaire.

9
ygaradon

On dirait que vous rendez la tâche plus difficile que nécessaire. Pourquoi ne pas simplement Join le thread après l’avoir signalé son arrêt?

class Program
{
    static void Main(string[] args)
    {
        Worker worker = new Worker();
        Thread t = new Thread(worker.DoWork);
        t.IsBackground = true;
        t.Start();

        while (true)
        {
            var keyInfo = Console.ReadKey();
            if (keyInfo.Key == ConsoleKey.C && keyInfo.Modifiers == ConsoleModifiers.Control)
            {
                worker.KeepGoing = false;
                break;
            }
        }
        t.Join();
    }
}

class Worker
{
    public bool KeepGoing { get; set; }

    public Worker()
    {
        KeepGoing = true;
    }

    public void DoWork()
    {
        while (KeepGoing)
        {
            Console.WriteLine("Ding");
            Thread.Sleep(200);
        }
    }
}
3
Ed Power

Des deux premiers c'est mieux

_quitEvent.WaitOne();

parce que dans le second le thread se réveille chaque milliseconde sera transformé en interruption du système d'exploitation qui est coûteux

2
Naveen

Il est également possible de bloquer le thread/programme en fonction d'un jeton d'annulation.

token.WaitHandle.WaitOne();

WaitHandle est signalé lorsque le jeton est annulé.

J'ai vu cette technique utilisée par Microsoft.Azure.WebJobs.JobHost, où le jeton provient d'une source de jeton d'annulation de WebJobsShutdownWatcher (un observateur de fichier qui termine le travail).

Cela donne un certain contrôle sur la fin du programme.

0
CRice

Vous devriez le faire comme si vous programmiez un service Windows. Vous n'utiliseriez jamais une instruction while, mais un délégué. WaitOne () est généralement utilisé en attendant que les threads soient mis au rebut. Thread.Sleep () n'est pas conseillé. Avez-vous pensé à utiliser System.Timers.Timer en utilisant cet événement pour rechercher un événement de fermeture? 

0
KenL