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

Why is the console window closing immediately once displayed my output?

我正在学习C通过遵循MSDN中的指南。

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

1
2
3
4
5
6
7
8
9
10
using System;

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


the issue here is that their Hello World Program is showing up then it would immediately close.
why is that?

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

如果您想让它保持打开状态以进行调试,您需要指示计算机在结束应用程序并关闭窗口之前等待按键。

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

或者,您可以通过在Visual Studio环境中按ctrl+f5启动应用程序而不附加调试程序,但这明显有一个缺点,即阻止您使用调试功能,而当您在正在传送应用程序。

最好的折衷办法可能是只在调试应用程序时调用Console.ReadLine方法,方法是将它包装在预处理器指令中。类似:

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

如果抛出未捕获的异常,您可能还希望窗口保持打开状态。为此,您可以将Console.ReadLine();放在finally块中:

1
2
3
4
5
6
7
8
9
10
11
#if DEBUG
    try
    {
        //...
    }
    finally
    {
        Console.WriteLine("Press enter to close...");
        Console.ReadLine();
    }
#endif


而不是使用

1
2
3
Console.Readline()
Console.Read()
Console.ReadKey()

您可以使用ctrl+f5(如果您在Visual Studio中)运行程序。然后,Visual Studio将保持控制台窗口打开,直到您按键。

注意:不能用这种方法调试代码。


对于ctrlf5f5,其行为相同。直接放在main方法结束之前。

10


我假设您不希望它在调试模式下关闭,是因为您希望查看变量的值等,所以最好在主函数的关闭""处插入一个断点。如果不需要调试,那么ctrl-f5是最佳选项。


程序立即关闭,因为没有任何东西阻止它关闭。在return 0;处插入断点或在return 0;前加Console.Read();以防止程序关闭。


或者,可以使用以下代码延迟关闭:

1
System.Threading.Thread.Sleep(1000);

注:Sleep使用毫秒。


如果要保持应用程序的打开状态,则必须执行一些操作,以保持其进程的活动状态。下面是最简单的例子,放在程序末尾:

1
while (true) ;

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

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

1
Application.Run();

这不会泄漏CPU并成功工作。

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

1
SpinWait.SpinUntil(() => false);

这也很好地工作,它主要包含一个while迭代器,该迭代器具有一个由上述lambda方法返回的否定条件。为什么这个CPU不超载?您可以在这里查看源代码;无论如何,它基本上要等待处理器的某个周期来保持指令的运行。

您还可以选择创建一个消息循环器,它在传递到下一个迭代之前查看挂起的消息并处理其中的每个消息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[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;
}

然后您可以通过这样的操作安全地循环:

1
2
while (true)
    ProcessMessageOnce();

更好的是,您可以将后两种解决方案混合在一起,将while迭代器替换为SpinWait.SpinUntil调用:

1
SpinWait.SpinUntil(ProcessMessageOnce);

另一种方法是在从主方法返回之前使用Debugger.Break()


代码已完成,若要继续,需要添加此代码:

1
Console.ReadLine();

1
Console.Read();


添加Read方法以显示输出。

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

使用console.read();以防止程序关闭,但请确保在返回语句之前添加Console.Read();代码,否则它将是不可访问的代码。

1
2
    Console.Read();
    return 0;

检查这个控制台。阅读


我有点晚了,但是:在Visual Studio 2019 for.NET核心项目中,默认情况下控制台不会自动关闭。您可以通过菜单工具→选项→调试→常规→在调试停止时自动关闭控制台来配置行为。如果控制台窗口自动关闭,请检查是否未设置上述设置。

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

1
2
3
4
5
6
7
8
<Project Sdk="Microsoft.NET.Sdk">

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

</Project>

旧样式的.NET框架项目仍然无条件地在末尾关闭控制台(从Visual Studio 16.0.1开始)。

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


以下是一种不涉及Console的方法:

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

这是C中控制台应用程序异步的答案。

控制台应用程序中的任何内容都不使用await,而是使用theAsyncMethod().GetAwaiter().GetResult();

例子

var result = await HttpClientInstance.SendAsync(message);

变成

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


程序执行完成后立即关闭。在这种情况下,当您使用cx1(0)时。这是预期的功能。如果您希望看到输出,那么可以手动在终端中运行它,或者在程序结束时设置一个等待,以便它保持打开几秒钟(使用线程库)。


简化别人的话:使用Console.ReadKey();

这使得程序等待用户按键盘上的正常键。

来源:我在我的控制台应用程序中使用它。


我总是将以下语句添加到控制台应用程序中。(如果愿意,请为此创建一个代码段)

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

当您想通过控制台应用程序试验不同的概念时,这样做会有所帮助。

ctr+f5将使控制台保持不变,但您无法调试!我在realworld中编写的所有控制台应用程序都是非交互式的,由诸如tws或ca工作站之类的调度程序触发,不需要这样的东西。


只需调用输入就可以很简单地解决这个问题。但是,如果按Enter,控制台将再次关闭。只需使用这个Console.ReadLine();Console.Read();


如果程序要求按Enter继续,如您必须输入一个值并继续,然后添加一个新的double或int在retunr(0)之前输入write;scanf_s("%lf",&the variable);


在返回0之前添加以下内容:

1
system("PAUSE");

这将打印一条线,点击一个键关闭窗口。它将使窗口一直打开,直到您按Enter键。我让我的学生把它添加到他们所有的程序中。


据我所知,如果要稳定控制台应用程序的输出,直到输出显示使用结束,标签:mainmethod之后,goto标签;程序结束之前

在程序中。

如:

1
2
3
4
5
6
7
8
static void Main(string[] args)
{
    label:

    // Snippet of code

    goto label;
}