Tại sao cửa sổ giao diện điều khiển đóng ngay lập tức khi hiển thị đầu ra của tôi?


158

Tôi đang học C # bằng cách làm theo các hướng dẫn trong MSDN .

Bây giờ, tôi vừa thử ví dụ 1 ( đây là liên kết đến MSDN ) và tôi đã gặp phải một vấn đề: tại sao cửa sổ giao diện điều khiển đóng ngay lập tức khi hiển thị đầu ra của tôi?

using System;

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

Bạn có thể thử mở bằng bàn điều khiển. Kéo và thả nó trên bàn điều khiển và nhấn "Enter". Tôi giả sử đó là một tập tin EXE.
Sajidur Rahman

Nếu bạn đang cố gắng DEBUG một chương trình dòng lệnh được bắt đầu bởi một quy trình bên ngoài, hãy xem câu hỏi này: stackoverflow.com/a/23334014/3195477
UuDdLrLrSs

Câu trả lời:


265

Vấn đề ở đây là Chương trình Hello World của họ đang hiển thị và nó sẽ ngay lập tức đóng lại.
tại sao vậy?

Bởi vì nó đã hoàn thành. Khi các ứng dụng bàn điều khiển đã hoàn thành thực thi và trở về từ mainphương thức của chúng , cửa sổ bàn điều khiển liên quan sẽ tự động đóng lại. Đây là hành vi dự kiến.

Nếu bạn muốn giữ cho nó mở cho mục đích gỡ lỗi, bạn sẽ cần hướng dẫn máy tính chờ nhấn phím trước khi kết thúc ứng dụng và đóng cửa sổ.

Các Console.ReadLinephương pháp là một cách để làm điều đó. Thêm dòng này vào cuối mã của bạn (ngay trước returncâu lệnh) sẽ khiến ứng dụng chờ bạn nhấn phím trước khi thoát.

Ngoài ra, bạn có thể khởi động ứng dụng mà không cần trình gỡ lỗi được đính kèm bằng cách nhấn Ctrl+ F5từ trong môi trường Visual Studio, nhưng điều này có nhược điểm rõ ràng là ngăn bạn sử dụng các tính năng gỡ lỗi mà bạn có thể muốn sử dụng khi viết ứng dụng.

Sự thỏa hiệp tốt nhất có lẽ là chỉ gọi Console.ReadLinephương thức khi gỡ lỗi ứng dụng bằng cách gói nó trong một chỉ thị tiền xử lý. Cái gì đó như:

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

Bạn cũng có thể muốn cửa sổ mở nếu một ngoại lệ chưa được phát hiện được ném ra. Để làm điều đó bạn có thể đặt Console.ReadLine();một finallykhối:

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

18
Thay phiên, bạn có thể sử dụng Console.ReadKey ();
PlantationGator

55
Cá nhân, tôi thích if (System.Diagnostics.Debugger.IsAttached) Console.ReadLine();.
Sameer Singh

5
Tại sao chạy mà không gỡ lỗi thay đổi hành vi đó? Bạn sẽ nghĩ đó là một trải nghiệm chính xác hơn chứ không phải ít hơn.
Kyle Delaney

@SameerSingh Thêm một dòng mã không cần thiết được biên dịch thành nhị phân của bạn. Tôi thực sự thích cách tiếp cận tiền xử lý này.
Joel

@Joel Tại sao chúng ta, nói chung, quan tâm đến điều đó những ngày này?
Alex

66

Thay vì sử dụng

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

bạn có thể chạy chương trình của mình bằng Ctrl+ F5(nếu bạn đang ở trong Visual Studio). Sau đó, Visual Studio sẽ giữ cửa sổ giao diện điều khiển mở, cho đến khi bạn nhấn một phím.

Lưu ý: Bạn không thể gỡ lỗi mã của mình theo cách tiếp cận này.


Chào người dùng. Tôi cũng là người dùng mới của VS và C # nói chung. Làm gì Ctrl + F5khác nhau mà đơn giản là đẹp Startlàm khác nhau?
theGreenCabbage

Thật không may, đôi khi nó dừng lại để làm việc như mong đợi.
MaikoID

2
Nguyên nhân của vấn đề là các cửa sổ tự động đóng cửa sổ đầu cuối khi chương trình dừng lại. Các hệ thống khác sẽ giữ cho Cửa sổ mở tự động. Đây là cách tốt hơn để chạy chương trình. Không sử dụng ReadKey, Read hoặc ReadLine cho nội dung này vì điều này ngăn chương trình của bạn được sử dụng kết hợp với các ứng dụng và đường ống điều khiển khác.
thời gian thực

14

Tôi giả sử lý do bạn không muốn nó đóng trong chế độ Gỡ lỗi, là vì bạn muốn xem các giá trị của biến, v.v. Vì vậy, tốt nhất là chỉ nên chèn một điểm dừng khi đóng "}" của hàm chính . Nếu bạn không cần gỡ lỗi, thì Ctrl-F5 là tùy chọn tốt nhất.


Ngạc nhiên không có câu trả lời khác đề nghị này. Thật hiếm khi một câu trả lời với một tùy chọn mới được thêm vào quá muộn sau khi câu hỏi được tạo.
Scott Chamberlain

13

Điều này hành xử tương tự cho CtrlF5hoặc F5. Đặt ngay trước khi kết thúc Mainphương pháp.

using System.Diagnostics;

private static void Main(string[] args) {

  DoWork();

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

7
Chỉ cần lưu ý, dòng cuối cùng nên Console.ReadKey()dành cho bất kỳ phím nào, Console.ReadLine()chờ nhấn để nhập
Chris

6

Chương trình ngay lập tức đóng cửa vì không có gì ngăn chặn nó đóng cửa. Chèn một điểm dừng tại return 0;hoặc thêm Console.Read();trước return 0;để ngăn chương trình đóng lại.


5

Tôi đến bữa tiệc muộn một chút, nhưng: trong Visual Studio 2019 cho các dự án .NET Core, bàn điều khiển không tự động đóng. Bạn có thể định cấu hình hành vi thông qua menu Công cụ → Tùy chọn → Gỡ lỗi → Chung → Tự động đóng bàn điều khiển khi dừng gỡ lỗi. Nếu bạn tự động đóng cửa sổ giao diện điều khiển, hãy kiểm tra xem cài đặt được đề cập chưa được đặt.

Điều tương tự cũng áp dụng cho các dự án giao diện điều khiển kiểu .NET Framework mới:

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

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

</Project>

Dự án .NET Framework kiểu cũ vẫn đóng vô điều kiện giao diện điều khiển ở cuối (kể từ Visual Studio 16.0.1).

Tham khảo: https://devbloss.microsoft.com/dotnet/net-core-tooling-update-for-visual-studio-2019-preview-2/


Tùy chọn này có sẵn cho tôi trong VS2017 15.9.4 nhưng nó không hoạt động cho ứng dụng bảng điều khiển .net core 2.1 của tôi ...
user1073075

@ user1073075: thật lạ. Liệu các tính năng làm việc cho các mục tiêu khác?
Vlad

Không. Đã thử với ứng dụng bảng điều khiển .NET framework và vẫn không hoạt động. (Tôi đã cài đặt VS2019 trên một máy khác và nó hoạt động. Có lẽ đó là một lỗi trong VS17 15.9.4)
user1073075

Với năm 2019, nó hoạt động ngay cả đối với các dự án WPF: pastebin.com/FpAeV0cW . Nhưng bạn phải cài đặt .NET Core 3.
Vlad

5

Nếu bạn muốn mở ứng dụng của mình, bạn phải làm một cái gì đó để giữ cho quá trình của nó tồn tại. Ví dụ dưới đây là ví dụ đơn giản nhất, được đặt ở cuối chương trình của bạn:

while (true) ;

Tuy nhiên, nó sẽ khiến CPU bị quá tải, do đó nó buộc phải lặp đi lặp lại vô hạn.

Tại thời điểm này, bạn có thể chọn sử dụng System.Windows.Forms.Applicationlớp (nhưng nó yêu cầu bạn thêm System.Windows.Formstham chiếu):

Application.Run();

Điều này không rò rỉ CPU và hoạt động thành công.

Để tránh thêm System.Windows.Formstham chiếu, bạn có thể sử dụng một mẹo đơn giản, cái gọi là chờ đợi , nhập System.Threading:

SpinWait.SpinUntil(() => false);

Điều này cũng hoạt động hoàn hảo, và về cơ bản nó bao gồm một whilevòng lặp với một điều kiện phủ định được trả về bởi phương thức lambda ở trên. Tại sao CPU này không quá tải? Bạn có thể xem mã nguồn ở đây ; dù sao, về cơ bản, nó chờ một số chu kỳ CPU trước khi lặp lại.

Bạn cũng có thể tạo một looper tin nhắn, trong đó nhìn trộm các tin nhắn đang chờ xử lý từ hệ thống và xử lý từng tin nhắn trước khi chuyển sang lần lặp tiếp theo, như sau:

[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;
}

Sau đó, bạn có thể lặp một cách an toàn bằng cách làm một cái gì đó như thế này:

while (true)
    ProcessMessageOnce();

Tôi không biết điều này có làm rò rỉ CPU hay không nhưng; hoạt động thành công. Cảm ơn bạn.
Mumin Ka

4

Ngoài ra, bạn có thể trì hoãn việc đóng bằng mã sau:

System.Threading.Thread.Sleep(1000);

Lưu ý Sleeplà sử dụng mili giây.


4

Một cách khác là sử dụng Debugger.Break()trước khi trở về từ phương thức chính


Mặc dù các công tắc này tập trung trở lại cửa sổ trình gỡ lỗi và có khả năng ẩn nội dung của cửa sổ giao diện điều khiển.
Stephen Turner

3

Mã đã kết thúc, để tiếp tục, bạn cần thêm phần này:

Console.ReadLine();

hoặc là

Console.Read();

3

Sử dụng Console.Read (); để ngăn chương trình đóng, nhưng hãy đảm bảo bạn thêm Console.Read();mã trước khi trả về câu lệnh, nếu không nó sẽ là mã không thể truy cập được.

    Console.Read(); 
    return 0; 

kiểm tra Bảng điều khiển này. Đọc


3

Thêm ReadPhương thức để hiển thị đầu ra.

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

1

Đây là một cách để làm điều đó mà không liên quan Console:

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

0

Chương trình sẽ kết thúc ngay sau khi hoàn thành. Trong trường hợp này khi bạn return 0;. Đây là chức năng dự kiến. Nếu bạn muốn xem đầu ra thì hãy chạy nó trong một thiết bị đầu cuối theo cách thủ công hoặc đặt chờ ở cuối chương trình để nó sẽ mở trong vài giây (sử dụng thư viện luồng).


0

Đây là câu trả lời không đồng bộ tại ứng dụng console trong C #?

bất cứ nơi nào trong ứng dụng giao diện điều khiển không bao giờ sử dụng awaitmà thay vào đó sử dụng theAsyncMethod().GetAwaiter().GetResult();,

thí dụ

var result = await HttpClientInstance.SendAsync(message);

trở thành

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


-3

nếu chương trình của bạn yêu cầu bạn nhấn enter để tiếp tục như bạn phải nhập một giá trị và tiếp tục, sau đó thêm một dấu kép hoặc int mới và gõ write trước khi retunr (0); scanf_s ("% lf", & biến);


1
Đây là một câu hỏi C # .
Ái Hà Lee

-3

Tôi luôn thêm câu lệnh sau vào ứng dụng bảng điều khiển. (Tạo đoạn mã cho điều này nếu bạn muốn)

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

Làm điều này sẽ giúp khi bạn muốn thử nghiệm các khái niệm khác nhau thông qua ứng dụng giao diện điều khiển.

Ctr + F5 sẽ khiến Console ở lại nhưng bạn không thể gỡ lỗi! Tất cả các ứng dụng bảng điều khiển mà tôi đã viết trong thế giới thực luôn không tương tác và được kích hoạt bởi Trình lập lịch biểu như trạm TWS hoặc CA Work và không yêu cầu thứ gì đó như thế này.


-3

Để đơn giản hóa những gì người khác đang nói: Sử dụng Console.ReadKey();.

Điều này làm cho nó để chương trình đang chờ người dùng nhấn một phím bình thường trên bàn phím

Nguồn: Tôi sử dụng nó trong các chương trình của mình cho các ứng dụng console.


-3

Bạn có thể giải quyết nó một cách rất đơn giản chỉ cần gọi đầu vào. Tuy nhiên, nếu bạn nhấn Enterthì bàn điều khiển sẽ biến mất một lần nữa. Đơn giản chỉ cần sử dụng cái này Console.ReadLine();hoặcConsole.Read();


-4

Thêm vào sau đây trước khi trả về 0:

system("PAUSE");  

Điều này in một dòng để nhấn một phím để đóng cửa sổ. Nó sẽ giữ cửa sổ lên cho đến khi bạn nhấn phím enter. Tôi có học sinh của tôi thêm nó vào tất cả các chương trình của họ.


1
đó là trong c ++
Gonçalo Garrido

-13

Theo mối quan tâm của tôi, nếu chúng tôi muốn ổn định ĐẦU RA ỨNG DỤNG TIÊU THỤ, cho đến khi đóng màn hình hiển thị đầu ra SỬ DỤNG, nhãn: sau nhãn MainMethod và nhãn goto; trước khi kết thúc chương trình

Trong chương trình.

ví dụ:

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

    // Snippet of code

    goto label;
}

2
Điều này sẽ khiến chương trình áp phích tiếp tục in "Xin chào, Thế giới!" nhiều lần
DavidPostill 23/07/14

1
Chúa ơi, không biết gototuyên bố thậm chí còn được cho phép trong C #.
Ch3shire
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.