it-swarm.com.de

Wie kann eine .NET-Konsolen-App ausgeführt werden?

Stellen Sie sich eine Konsolenanwendung vor, die einige Dienste in einem separaten Thread startet. Sie müssen lediglich warten, bis der Benutzer Strg + C drückt, um ihn herunterzufahren. 

Welcher der folgenden ist der bessere Weg, dies zu tun?

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
}

Oder dies mit 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

sie möchten immer die Verwendung von while-Schleifen verhindern, insbesondere wenn Sie den Code dazu zwingen, Variablen erneut zu prüfen. Es verschwendet CPU-Ressourcen und verlangsamt Ihr Programm.

Ich würde definitiv die erste sagen.

58
Mike

Alternativ ist eine einfachere Lösung nur:

Console.ReadLine();
27
Cocowalla

Sie können dies tun (und den Ereignishandler CancelKeyPress entfernen):

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

Nicht sicher, ob das besser ist, aber ich mag die Idee nicht, Thread.Sleep in einer Schleife aufzurufen. Ich denke, es ist sauberer, die Benutzereingaben zu blockieren.

11
Thomas Levesque

Ich bevorzuge die Application.Run

static void Main(string[] args) {

   //Do your stuff here

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

   //Cleanup/Before Quit
}

aus den docs: 

Beginnt mit der Ausführung einer Standardanwendungsnachrichtenschleife für den aktuellen Thread ohne Formular.

9
ygaradon

Scheint, als ob Sie es schwieriger machen, als Sie brauchen. Warum nicht einfach Join den Thread, nachdem Sie signalisiert haben, dass er aufhört?

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

Von den beiden ist der erste besser

_quitEvent.WaitOne();

weil im zweiten Thread der Thread jede Millisekunde aufwacht, wird er in OS Interrupt verwandelt, was teuer ist

2
Naveen

Es ist auch möglich, den Thread/das Programm basierend auf einem Abbruchtoken zu blockieren.

token.WaitHandle.WaitOne();

WaitHandle wird signalisiert, wenn das Token abgebrochen wird.

Ich habe diese von Microsoft.Azure.WebJobs.JobHost verwendete Technik gesehen, bei der das Token aus einer Absage-Token-Quelle des WebJobsShutdownWatcher stammt (einer Dateiüberwachung, die den Job beendet).

Dies gibt eine gewisse Kontrolle darüber, wann das Programm enden kann.

0
CRice

Sie sollten es genauso tun, als würden Sie einen Windows-Dienst programmieren. Sie würden niemals eine while-Anweisung verwenden, sondern einen Delegaten. WaitOne () wird im Allgemeinen verwendet, während gewartet wird, dass Threads entsorgt werden. - Thread.Sleep () - ist nicht ratsam. 

0
KenL