Dlaczego okno konsoli zamyka się natychmiast po wyświetleniu mojego wyniku?


158

Studiuję C #, postępując zgodnie z przewodnikami w MSDN .

Teraz właśnie wypróbowałem przykład 1 ( tutaj jest łącze do MSDN ) i napotkałem problem: dlaczego okno konsoli zamyka się natychmiast po wyświetleniu moich danych wyjściowych?

using System;

public class Hello1
{
    public static int Main()
    {
        Console.WriteLine("Hello, World!");
        return 0;
    }
}

Możesz spróbować otworzyć za pomocą konsoli. Przeciągnij i upuść na konsoli i naciśnij „Enter”. Zakładam, że jest to plik EXE.
Sajidur Rahman

Jeśli próbujesz DEBUGOWAĆ program wiersza poleceń, który jest uruchamiany przez proces zewnętrzny, zobacz to pytanie: stackoverflow.com/a/23334014/3195477
UuDdLrLrSs

Odpowiedzi:


266

problem polega na tym, że ich program Hello World pojawia się, a następnie zostanie natychmiast zamknięty.
dlaczego?

Ponieważ jest skończone. Gdy aplikacje konsolowe zakończą wykonywanie i powrócą ze swojej mainmetody, skojarzone okno konsoli zostanie automatycznie zamknięte. Jest to oczekiwane zachowanie.

Jeśli chcesz, aby była otwarta do celów debugowania, musisz poinstruować komputer, aby czekał na naciśnięcie klawisza przed zamknięciem aplikacji i zamknięciem okna.

Console.ReadLineMetoda jest jednym ze sposobów na osiągnięcie tego. Dodanie tego wiersza na końcu kodu (tuż przed returninstrukcją) spowoduje, że aplikacja zaczeka na naciśnięcie klawisza przed wyjściem.

Alternatywnie możesz uruchomić aplikację bez dołączonego debugera, naciskając Ctrl+ F5z poziomu środowiska Visual Studio, ale ma to oczywistą wadę, ponieważ uniemożliwia korzystanie z funkcji debugowania, które prawdopodobnie chcesz mieć do dyspozycji podczas pisania aplikacji.

Najlepszym kompromisem jest prawdopodobnie wywoływanie Console.ReadLinemetody tylko podczas debugowania aplikacji poprzez umieszczenie jej w dyrektywie preprocesora. Coś jak:

#if DEBUG
    Console.WriteLine("Press enter to close...");
    Console.ReadLine();
#endif

Możesz także chcieć, aby okno pozostało otwarte, jeśli został zgłoszony nieprzechwycony wyjątek. Aby to zrobić, możesz umieścić Console.ReadLine();w finallybloku:

#if DEBUG
    try
    {
        //...
    }
    finally
    {
        Console.WriteLine("Press enter to close...");
        Console.ReadLine();
    }
#endif

18
Alternatywnie możesz użyć Console.ReadKey ();
PlantationGator

55
Osobiście wolę if (System.Diagnostics.Debugger.IsAttached) Console.ReadLine();.
Sameer Singh

5
Dlaczego uruchamianie bez debugowania zmienia to zachowanie? Można by pomyśleć, że powinno to być dokładniejsze doświadczenie, a nie mniej.
Kyle Delaney,

@SameerSingh Jeszcze jedna linia niepotrzebnego kodu kompilowana do twojego pliku binarnego. Właściwie wolę to podejście preprocesora.
Joel

@Joel Dlaczego w ogóle powinno nas to obchodzić w dzisiejszych czasach?
Alex

66

Zamiast używać

Console.Readline()
Console.Read()
Console.ReadKey()

możesz uruchomić swój program za pomocą Ctrl+ F5(jeśli jesteś w Visual Studio). Następnie program Visual Studio pozostawi otwarte okno konsoli do momentu naciśnięcia klawisza.

Uwaga: w ten sposób nie można debugować kodu.


Cześć użytkowniku. Jestem nowym użytkownikiem VS i C # w ogóle. Co robi Ctrl + F5inaczej, a co po prostu całkiem Startinaczej?
theGreenCabbage

niestety czasami przestaje działać zgodnie z oczekiwaniami.
MaikoID

2
Przyczyną problemu jest to, że system Windows automatycznie zamyka okno terminala po zatrzymaniu programu. Inne systemy automatycznie utrzymują okno otwarte. To o wiele lepszy sposób na uruchomienie programu. Nie używaj ReadKey, Read lub ReadLine do tych rzeczy, ponieważ zapobiega to używaniu twojego programu w połączeniu z innymi aplikacjami konsolowymi i potokami.
czasie rzeczywistym

14

Zakładam, że powodem, dla którego nie chcesz, aby zamykał się w trybie debugowania, jest to, że chcesz spojrzeć na wartości zmiennych itp. Więc prawdopodobnie najlepiej jest po prostu wstawić punkt przerwania na zamykającym "}" funkcji głównej . Jeśli nie musisz debugować, najlepszym rozwiązaniem jest Ctrl-F5.


Zaskoczony, żadna z pozostałych odpowiedzi tego nie sugerowała. Rzadko zdarza się, aby odpowiedź z nową opcją została dodana tak późno po utworzeniu pytania.
Scott Chamberlain

13

Zachowuje się to tak samo w przypadku CtrlF5lub F5. Miejsce bezpośrednio przed zakończeniem Mainmetody.

using System.Diagnostics;

private static void Main(string[] args) {

  DoWork();

  if (Debugger.IsAttached) {
    Console.WriteLine("Press any key to continue . . .");
    Console.ReadLine();
  }
}

7
Uwaga, ostatnia linia powinna być Console.ReadKey()dla dowolnego klawisza, Console.ReadLine()czeka na naciśnięcie klawisza Enter
Chris

6

Program zamyka się natychmiast, ponieważ nic go nie powstrzymuje. Wstaw punkt przerwania na return 0;lub dodaj Console.Read();przed, return 0;aby zapobiec zamknięciu programu.


5

Trochę się spóźniłem na imprezę, ale: w Visual Studio 2019 dla projektów .NET Core konsola domyślnie nie zamyka się automatycznie. Możesz skonfigurować zachowanie za pomocą menu Narzędzia → Opcje → Debugowanie → Ogólne → Automatycznie zamknij konsolę po zatrzymaniu debugowania. Jeśli okno konsoli zostanie automatycznie zamknięte, sprawdź, czy wspomniane ustawienie nie jest ustawione.

To samo dotyczy projektów konsoli nowego stylu .NET Framework:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net472</TargetFramework>
  </PropertyGroup>

</Project>

Projekt .NET Framework w starym stylu nadal bezwarunkowo zamyka konsolę na końcu (od Visual Studio 16.0.1).

Źródła: https://devblogs.microsoft.com/dotnet/net-core-tooling-update-for-visual-studio-2019-preview-2/


Ta opcja jest dostępna dla mnie w VS2017 15.9.4, ale nie działa w mojej aplikacji konsoli .net core 2.1 ...
user1073075

@ user1073075: to jest dziwne. Czy funkcja działa w przypadku innych celów?
Vlad

Nie. Próbowałem z aplikacją konsoli .NET Framework i nadal nie działało. (Zainstalowałem VS2019 na innym komputerze i już działa. Może to błąd w VS17 15.9.4)
user1073075

Z 2019 działa teraz nawet dla projektów WPF: pastebin.com/FpAeV0cW . Ale musisz zainstalować .NET Core 3.
Vlad

5

Jeśli chcesz, aby Twoja aplikacja pozostała otwarta, musisz coś zrobić, aby utrzymać jej proces. Poniższy przykład jest najprostszym przykładem, który należy umieścić na końcu programu:

while (true) ;

Jednak spowoduje to przeciążenie procesora, ponieważ w związku z tym jest zmuszony do nieskończonej iteracji.

W tym momencie możesz zdecydować się na użycie System.Windows.Forms.Applicationklasy (ale wymaga to dodania System.Windows.Formsreferencji):

Application.Run();

To nie powoduje wycieku procesora i działa pomyślnie.

Aby uniknąć dodawania System.Windows.Formsreferencji, możesz skorzystać z prostego triku, tzw. Czekania spinowego , importującego System.Threading:

SpinWait.SpinUntil(() => false);

Działa to również doskonale i zasadniczo składa się z whilepętli z zanegowanym warunkiem, który jest zwracany przez powyższą metodę lambda. Dlaczego to nie przeciąża procesora? Możesz spojrzeć na kod źródłowy tutaj ; w każdym razie po prostu czeka jakiś cykl procesora przed iteracją.

Możesz także utworzyć pętlę komunikatów, która przegląda oczekujące wiadomości z systemu i przetwarza każdą z nich przed przejściem do następnej iteracji, w następujący sposób:

[DebuggerHidden, DebuggerStepperBoundary, DebuggerNonUserCode, DllImport("user32.dll", EntryPoint = "PeekMessage")]
public static extern int PeekMessage(out NativeMessage lpMsg, IntPtr hWnd, int wMsgFilterMin, int wMsgFilterMax, int wRemoveMsg);

[DebuggerHidden, DebuggerStepperBoundary, DebuggerNonUserCode, DllImport("user32.dll", EntryPoint = "GetMessage")]
public static extern int GetMessage(out NativeMessage lpMsg, IntPtr hWnd, int wMsgFilterMin, int wMsgFilterMax);

[DebuggerHidden, DebuggerStepperBoundary, DebuggerNonUserCode, DllImport("user32.dll", EntryPoint = "TranslateMessage")]
public static extern int TranslateMessage(ref NativeMessage lpMsg);

[DebuggerHidden, DebuggerStepperBoundary, DebuggerNonUserCode, DllImport("user32.dll", EntryPoint = "DispatchMessage")]
public static extern int DispatchMessage(ref NativeMessage lpMsg);

[DebuggerHidden, DebuggerStepperBoundary, DebuggerNonUserCode]
public static bool ProcessMessageOnce()
{
    NativeMessage message = new NativeMessage();

    if (!IsMessagePending(out message))
        return true;

    if (GetMessage(out message, IntPtr.Zero, 0, 0) == -1)
        return true;

    Message frameworkMessage = new Message()
    {
        HWnd = message.handle,
        LParam = message.lParam,
        WParam = message.wParam,
        Msg = (int)message.msg
    };

    if (Application.FilterMessage(ref frameworkMessage))
        return true;

    TranslateMessage(ref message);
    DispatchMessage(ref message);

    return false;
}

Następnie możesz bezpiecznie zapętlić, wykonując coś takiego:

while (true)
    ProcessMessageOnce();

Nie wiem, czy to przecieka procesor, czy nie, ale; działa pomyślnie. Dziękuję Ci.
Mumin Ka

4

Alternatywnie możesz opóźnić zamknięcie za pomocą następującego kodu:

System.Threading.Thread.Sleep(1000);

Zwróć uwagę, że Sleepużywa milisekund.


4

Innym sposobem jest użycie Debugger.Break()przed powrotem z metody Main


Mimo to przełącza fokus z powrotem do okna debugera i potencjalnie ukrywa zawartość okna konsoli.
Stephen Turner

3

Kod jest gotowy, aby kontynuować, musisz dodać to:

Console.ReadLine();

lub

Console.Read();

3

Użyj Console.Read (); aby zapobiec zamknięciu programu, ale upewnij się, że dodałeś Console.Read();kod przed instrukcją return, w przeciwnym razie będzie to kod nieosiągalny.

    Console.Read(); 
    return 0; 

sprawdź ten Console.Read


3

Add ReadMetoda wyświetlania danych wyjściowych.

Console.WriteLine("Hello, World!");
Console.Read();
return 0;

1

Oto sposób na zrobienie tego bez angażowania się Console:

var endlessTask = new TaskCompletionSource<bool>().Task;
endlessTask.Wait();

0

Program jest zamykany natychmiast po zakończeniu wykonywania. W tym przypadku, gdy ty return 0;. Jest to oczekiwana funkcjonalność. Jeśli chcesz zobaczyć dane wyjściowe, uruchom je ręcznie w terminalu lub ustaw czekanie na końcu programu, aby pozostał otwarty przez kilka sekund (używając biblioteki wątków).


0

to jest odpowiedź asynchroniczna w aplikacji konsoli w C #?

wszystko, gdziekolwiek w aplikacji konsoli, nigdy nie używa, awaitale zamiast tego używa theAsyncMethod().GetAwaiter().GetResult();,

przykład

var result = await HttpClientInstance.SendAsync(message);

staje się

var result = HttpClientInstance.SendAsync(message).GetAwaiter().GetResult();


-3

jeśli twój program wymaga naciśnięcia klawisza enter, aby kontynuować, tak jak musisz wprowadzić wartość i kontynuować, dodaj nowe podwójne lub int i wpisz write przed retunr (0); scanf_s ("% lf", & zmienna);


1
To jest pytanie w języku C # .
Wai Ha Lee

-3

Zawsze dodaję następującą instrukcję do aplikacji konsoli. (Jeśli chcesz, utwórz dla tego fragment kodu)

Console.WriteLine("Press any key to quit!");
Console.ReadKey();

Takie postępowanie pomaga, gdy chcesz eksperymentować z różnymi koncepcjami za pomocą aplikacji konsolowej.

Ctr + F5 sprawi, że konsola pozostanie, ale nie możesz debugować! Wszystkie aplikacje konsolowe, które napisałem w realworld, są zawsze nieinteraktywne i uruchamiane przez harmonogram, taki jak stacja robocza TWS lub CA, i nie wymagały czegoś takiego.


-3

Aby uprościć to, co mówią inni: Użyj Console.ReadKey();.

To sprawia, że ​​program czeka, aż użytkownik naciśnie normalny klawisz na klawiaturze

Źródło: używam go w moich programach dla aplikacji konsolowych.


-3

Możesz rozwiązać ten problem w bardzo prosty sposób, po prostu wywołując dane wejściowe. Jeśli jednak naciśniesz, Enterkonsola ponownie zniknie. Po prostu użyj tego Console.ReadLine();lubConsole.Read();


-4

Dodaj co następuje przed zwrotem 0:

system("PAUSE");  

Spowoduje to wyświetlenie linii, w której należy nacisnąć klawisz, aby zamknąć okno. Utrzyma okno aż do naciśnięcia klawisza Enter. Mam moich uczniów, którzy dodają go do wszystkich swoich programów.


1
to jest w c ++
Gonçalo Garrido

-13

Zgodnie z moimi obawami, jeśli chcemy ustabilizować WYJŚCIE APLIKACJI KONSOLI, aż do zamknięcia wyjścia wyświetli się napis USE, etykieta: po MainMethod i etykieta goto; przed zakończeniem programu

W programie.

na przykład:

static void Main(string[] args)
{
    label:

    // Snippet of code

    goto label;
}

2
Spowoduje to po prostu drukowanie przez program plakatów „Hello, World!” wiele razy
DavidPostill

1
Jezu Chryste, nie wiedziałem, że gotozeznanie jest dozwolone nawet w C #.
Ch3shire
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.