为什么控制台窗口会在显示输出后立即关闭?

use*_*206 151 .net c# msdn console-application

我正在按照MSDN中的指南学习C#.

现在,我刚刚尝试了示例1(这里MSDN的链接),我遇到了一个问题:为什么控制台窗口会在显示输出后立即关闭?

using System;

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

Cod*_*ray 257

这里的问题是他们的Hello World计划出现了,然后它会立即关闭.
这是为什么?

因为它已经完成了.当控制台应用程序完成执行并从其main方法返回时,关联的控制台窗口将自动关闭.这是预期的行为.

如果要将其保持打开以进行调试,则需要指示计算机在结束应用程序并关闭窗口之前等待按键操作.

Console.ReadLine方法是这样做的一种方式.将此行添加到代码的末尾(就在return语句之前)将导致应用程序在退出之前等待您按下某个键.

或者,您可以通过在Visual Studio环境中按Ctrl+ 来启动没有附加调试器的应用程序F5,但这有一个明显的缺点,即阻止您使用调试功能,在编写应用程序时您可能需要这些功能.

最好的折衷方案可能是Console.ReadLine仅在调试应用程序时通过将其包装在预处理程序指令中来调用该方法.就像是:

#if DEBUG
    Console.WriteLine("Press enter to close...");
    Console.ReadLine();
#endif
Run Code Online (Sandbox Code Playgroud)

如果抛出未捕获的异常,您可能还希望窗口保持打开状态.要做到这一点,你可以把它Console.ReadLine();放在一个finally块中:

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

  • 就个人而言,我更喜欢`if(System.Diagnostics.Debugger.IsAttached)Console.ReadLine();`. (50认同)
  • 或者,您可以使用Console.ReadKey(); (18认同)
  • 为什么没有调试运行会改变这种行为?你认为它应该是一种更准确的体验,而不是更少. (4认同)

Bha*_*tel 64

而不是使用

Console.Readline()
Console.Read()
Console.ReadKey()
Run Code Online (Sandbox Code Playgroud)

您可以使用Ctrl+ 运行程序F5(如果您在Visual Studio中).然后,Visual Studio将保持控制台窗口打开,直到您按下某个键.

注意:您无法使用此方法调试代码.

  • 问题的原因是程序停止时Windows会自动关闭终端窗口.其他系统将自动打开窗口.这是运行程序的更好方法.不要使用ReadKey,Read或ReadLine来处理这些问题,因为这会阻止您的程序与其他控制台应用程序和管道一起使用. (2认同)

use*_*993 13

对于CtrlF5或,这表现相同F5.在Main方法结束前立即放置.

using System.Diagnostics;

private static void Main(string[] args) {

  DoWork();

  if (Debugger.IsAttached) {
    Console.WriteLine("Press any key to continue . . .");
    Console.ReadLine();
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 需要注意的是,对于任何键,最后一行应该是`Console.ReadKey()`,`Console.ReadLine()`等待输入被按下 (6认同)

Rob*_*b L 11

我假设您不希望它在调试模式下关闭的原因是因为您想要查看变量等的值.所以最好只在主函数的结束"}"上插入一个断点. .如果您不需要调试,则Ctrl-F5是最佳选择.

  • 令人惊讶的是其他答案都没有表明这一点。在问题创建后这么晚才添加带有新选项的答案的情况很少见。 (2认同)

Vla*_*lad 7

我参加聚会有点晚了,但是:在用于 .NET Core 项目的 Visual Studio 2019 中,默认情况下控制台不会自动关闭。您可以通过菜单工具配置行为?选项 ?调试 ? 一般的 ?调试停止时自动关闭控制台。如果您的控制台窗口自动关闭,请检查上述设置是否未设置。

这同样适用于 .NET Framework 新样式控制台项目:

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

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

</Project>
Run Code Online (Sandbox Code Playgroud)

旧式 .NET Framework 项目最后仍然无条件关闭控制台(从 Visual Studio 16.0.1 开始)。

参考:https : //devblogs.microsoft.com/dotnet/net-core-tooling-update-for-visual-studio-2019-preview-2/


Rob*_*ani 6

该程序立即关闭,因为没有什么能阻止它关闭.在return 0;Console.Read();之前插入断点return 0;以防止程序关闭.


Dav*_*zzo 5

如果你想保持你的应用程序打开,你必须做一些事情来保持它的进程活跃。下面的例子是最简单的例子,放在程序的末尾:

while (true) ;
Run Code Online (Sandbox Code Playgroud)

但是,它会导致 CPU 过载,因为它因此被迫无限迭代。

此时,您可以选择使用System.Windows.Forms.Application类(但它需要您添加System.Windows.Forms引用):

Application.Run();
Run Code Online (Sandbox Code Playgroud)

这不会泄漏 CPU 并成功运行。

为了避免添加System.Windows.Forms引用,可以使用一个简单的技巧,即所谓的自旋等待,导入System.Threading

SpinWait.SpinUntil(() => false);
Run Code Online (Sandbox Code Playgroud)

这也很完美,它基本上由一个while带有否定条件的循环组成,该循环由上述 lambda 方法返回。为什么这不会使 CPU 过载?你可以在这里查看源代码;无论如何,它在迭代之前基本上会等待一些 CPU 周期。

您还可以创建一个消息循环程序,它会从系统中查看待处理的消息并在传递到下一次迭代之前处理每个消息,如下所示:

[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;
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过执行以下操作来安全地循环:

while (true)
    ProcessMessageOnce();
Run Code Online (Sandbox Code Playgroud)