เหตุใดหน้าต่างคอนโซลปิดทันทีเมื่อแสดงผลลัพธ์ของฉัน


158

ฉันเรียน C # โดยทำตามคำแนะนำในMSDN

ตอนนี้ฉันลองตัวอย่างที่ 1 ( นี่คือลิงค์ไปที่MSDN ) และฉันพบปัญหา: ทำไมหน้าต่างคอนโซลปิดทันทีเมื่อแสดงผลลัพธ์ของฉัน

using System;

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

คุณสามารถลองเปิดด้วยคอนโซล ลากและวางบนคอนโซลแล้วกด "Enter" ฉันถือว่าไฟล์ EXE
Sajidur Rahman

หากคุณพยายามที่จะดีบักโปรแกรมบรรทัดคำสั่งซึ่งเริ่มต้นโดยกระบวนการภายนอกดูคำถามนี้: stackoverflow.com/a/23334014/3195477
UuDdLrLrSs

คำตอบ:


266

ปัญหาที่นี่คือโปรแกรม Hello World ปรากฏขึ้นจากนั้นจะปิดทันที
ทำไมถึงเป็นอย่างนั้น?

เพราะมันเสร็จแล้ว เมื่อแอปพลิเคชันคอนโซลดำเนินการและกลับมาจากmainวิธีการเสร็จสิ้นหน้าต่างคอนโซลที่เกี่ยวข้องจะปิดโดยอัตโนมัติ นี่เป็นพฤติกรรมที่คาดหวัง

หากคุณต้องการเปิดไว้เพื่อการดีบักคุณจะต้องสั่งให้คอมพิวเตอร์รอการกดปุ่มก่อนที่จะสิ้นสุดแอพและปิดหน้าต่าง

Console.ReadLineวิธีเป็นวิธีหนึ่งในการทำที่ การเพิ่มบรรทัดนี้ในตอนท้ายของรหัสของคุณ (ก่อนหน้าreturnคำสั่ง) จะทำให้แอปพลิเคชันรอให้คุณกดปุ่มก่อนที่จะออก

หรือคุณสามารถเริ่มแอปพลิเคชันโดยไม่ต้องดีบักเกอร์ที่แนบมาด้วยการกดCtrl+ F5จากภายในสภาพแวดล้อมของ Visual Studio แต่สิ่งนี้มีข้อเสียที่ชัดเจนในการป้องกันไม่ให้คุณใช้คุณสมบัติการดีบักซึ่งคุณอาจต้องการเมื่อทำการเขียนแอปพลิเคชัน

การประนีประนอมที่ดีที่สุดน่าจะเรียกConsole.ReadLineเมธอดนี้เฉพาะเมื่อทำการดีบั๊กแอปพลิเคชันโดยหุ้มไว้ในคำสั่งพรีโปรเซสเซอร์ สิ่งที่ต้องการ:

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

คุณอาจต้องการให้หน้าต่างเปิดอยู่หากมีข้อยกเว้นที่ไม่ได้ตรวจสอบ ทำที่คุณสามารถใส่Console.ReadLine();ในfinallyบล็อก:

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

18
คุณสามารถใช้ Console.ReadKey ();
PlantationGator

55
if (System.Diagnostics.Debugger.IsAttached) Console.ReadLine();ส่วนตัวผมชอบ
Sameer Singh

5
เหตุใดการทำงานโดยไม่แก้ไขจุดบกพร่องจึงเปลี่ยนพฤติกรรมนั้น คุณคิดว่ามันควรจะเป็นประสบการณ์ที่แม่นยำมากขึ้นไม่น้อย
Kyle Delaney

@SameerSingh อีกหนึ่งบรรทัดของโค้ดที่ไม่จำเป็นซึ่งถูกรวบรวมไว้ในไบนารีของคุณ ฉันชอบวิธี preprocessor นี้จริง ๆ
โจเอล

@Joel ทำไมโดยทั่วไปแล้วเราควรใส่ใจเกี่ยวกับวันนั้นเหรอ?
Alex

66

แทนที่จะใช้

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

คุณสามารถรันโปรแกรมโดยใช้Ctrl+ F5(ถ้าคุณอยู่ใน Visual Studio) จากนั้น Visual Studio จะเปิดหน้าต่างคอนโซลไว้จนกว่าคุณจะกดปุ่ม

หมายเหตุ: คุณไม่สามารถดีบักรหัสของคุณในวิธีการนี้


สวัสดีผู้ใช้ ฉันเป็นผู้ใช้ใหม่กับ VS และ C # โดยทั่วไปเช่นกัน อะไรที่Ctrl + F5แตกต่างกันที่ทำให้สวยStartแตกต่างกันบ้าง?
theGreenCabbage

น่าเสียดายที่บางครั้งมันหยุดทำงานตามที่คาดไว้
MaikoID

2
สาเหตุของปัญหาคือ windows ปิดหน้าต่างเทอร์มินัลโดยอัตโนมัติเมื่อโปรแกรมหยุดทำงาน ระบบอื่น ๆ จะเปิดหน้าต่างโดยอัตโนมัติ นี่เป็นวิธีที่ดีกว่าในการเรียกใช้โปรแกรม อย่าใช้ ReadKey, Read หรือ ReadLine สำหรับสิ่งนี้เนื่องจากจะเป็นการป้องกันไม่ให้โปรแกรมของคุณถูกใช้ร่วมกับแอปพลิเคชั่นคอนโซลและ piping อื่น ๆ
เรียลไทม์

14

ฉันถือว่าเหตุผลที่คุณไม่ต้องการให้มันปิดในโหมด Debug เพราะคุณต้องการดูค่าของตัวแปร ฯลฯ ดังนั้นมันอาจจะดีที่สุดถ้าคุณใส่จุดพักในการปิด "}" ของฟังก์ชั่นหลัก . หากคุณไม่จำเป็นต้องทำการดีบัก Ctrl-F5 เป็นตัวเลือกที่ดีที่สุด


แปลกใจที่ไม่มีคำตอบอื่น ๆ ที่แนะนำนี้ เป็นเรื่องยากที่คำตอบด้วยตัวเลือกใหม่ที่เพิ่มเข้ามาหลังจากที่คำถามถูกสร้างขึ้น
Scott Chamberlain

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();
  }
}

7
เพิ่งทราบว่าบรรทัดสุดท้ายควรเป็นConsole.ReadKey()กุญแจใด ๆConsole.ReadLine()รอการกดเพื่อป้อน
Chris

6

โปรแกรมจะปิดทันทีเนื่องจากไม่มีสิ่งใดที่จะหยุดไม่ให้ปิด แทรกเบรกพอยต์ที่return 0;หรือเพิ่มConsole.Read();ก่อนreturn 0;เพื่อป้องกันไม่ให้โปรแกรมปิด


5

ฉันมาช้าไปงานปาร์ตี้ แต่: ใน Visual Studio 2019 สำหรับโครงการ. NET Core คอนโซลจะไม่ปิดโดยอัตโนมัติตามค่าเริ่มต้น คุณสามารถกำหนดค่าพฤติกรรมผ่านเมนูเครื่องมือ→ตัวเลือก→การดีบั๊ก→ทั่วไป→ปิดคอนโซลโดยอัตโนมัติเมื่อการดีบั๊กหยุด ถ้าคุณได้รับหน้าต่างคอนโซลของคุณปิดโดยอัตโนมัติตรวจสอบว่าการตั้งค่าที่กล่าวถึงไม่ได้ตั้งค่า

เช่นเดียวกับโครงการคอนโซลสไตล์ใหม่ของ. NET Framework:

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

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

</Project>

โครงการ. NET Framework แบบเก่ายังคงปิดคอนโซลอย่างไม่มีเงื่อนไขในตอนท้าย (ตั้งแต่ Visual Studio 16.0.1)

การอ้างอิง: https://devblogs.microsoft.com/dotnet/net-core-tooling-update-for-visual-studio-2019-preview-2/


ตัวเลือกนี้มีให้สำหรับฉันใน VS2017 15.9.4 แต่ไม่สามารถใช้งานได้กับแอปพลิเคชันคอนโซล. net core 2.1 ของฉัน ...
1073075

@ user1073075: มันแปลก คุณสมบัตินี้ใช้งานได้กับเป้าหมายอื่น ๆ หรือไม่?
Vlad

ไม่ได้ลองใช้แอปคอนโซล NET Framework และยังใช้งานไม่ได้ (ฉันติดตั้ง VS2019 บนเครื่องที่แตกต่างกันและใช้งานได้อาจเป็นข้อผิดพลาดใน VS17 15.9.4)
user1073075

ด้วย 2019 ก็ทำงานตอนนี้แม้แต่สำหรับโครงการ WPF: pastebin.com/FpAeV0cW แต่คุณจะต้องติดตั้ง .NET แกน 3
ลาด

5

หากคุณต้องการให้แอปพลิเคชันของคุณเปิดอยู่คุณต้องทำอะไรบางอย่างเพื่อให้กระบวนการใช้งานได้ ตัวอย่างด้านล่างเป็นตัวอย่างที่ง่ายที่สุดที่จะนำมาวางที่ส่วนท้ายของโปรแกรมของคุณ:

while (true) ;

อย่างไรก็ตามมันจะทำให้ซีพียูโอเวอร์โหลดเนื่องจากมันถูกบังคับให้ทำซ้ำอย่างไม่ จำกัด

ณ จุดนี้คุณสามารถเลือกที่จะใช้System.Windows.Forms.Applicationคลาส (แต่คุณต้องเพิ่มSystem.Windows.Formsการอ้างอิง):

Application.Run();

สิ่งนี้ไม่ทำให้ CPU รั่วไหลและทำงานได้สำเร็จ

เพื่อหลีกเลี่ยงการเพิ่มSystem.Windows.Formsการอ้างอิงคุณสามารถใช้เคล็ดลับง่ายๆที่เรียกว่าหมุนรอคอยการนำเข้าSystem.Threading:

SpinWait.SpinUntil(() => false);

สิ่งนี้ยังทำงานได้อย่างสมบูรณ์และโดยทั่วไปประกอบด้วยwhileลูปที่มีเงื่อนไขที่ส่งคืนโดยวิธีแลมบ์ดาด้านบน ทำไม 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;
}

จากนั้นคุณสามารถวนลูปได้อย่างปลอดภัยโดยทำสิ่งนี้:

while (true)
    ProcessMessageOnce();

ฉันไม่รู้ว่า CPU ตัวนี้รั่วหรือเปล่า แต่; ทำงานได้สำเร็จ ขอบคุณ.
Mumin Ka

4

คุณสามารถหน่วงเวลาการปิดโดยใช้รหัสต่อไปนี้:

System.Threading.Thread.Sleep(1000);

โปรดทราบว่าSleepกำลังใช้มิลลิวินาที


4

อีกวิธีคือใช้Debugger.Break()ก่อนกลับจากวิธีหลัก


แม้ว่าสวิตช์นี้จะโฟกัสกลับไปที่หน้าต่างดีบักเกอร์และอาจซ่อนเนื้อหาของหน้าต่างคอนโซล
Stephen Turner

3

รหัสเสร็จสิ้นเพื่อดำเนินการต่อคุณต้องเพิ่มสิ่งนี้:

Console.ReadLine();

หรือ

Console.Read();

3

ใช้ Console.Read (); เพื่อป้องกันไม่ให้โปรแกรมปิด แต่ให้แน่ใจว่าคุณเพิ่มConsole.Read();รหัสก่อนที่จะส่งคืนคำสั่งมิฉะนั้นจะเป็นรหัสที่ไม่สามารถเข้าถึงได้

    Console.Read(); 
    return 0; 

ตรวจสอบConsoleนี้อ่าน



1

นี่เป็นวิธีที่จะทำโดยไม่เกี่ยวข้องConsole:

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

0

โปรแกรมจะปิดทันทีที่การดำเนินการเสร็จสมบูรณ์ return 0;ในกรณีนี้เมื่อคุณ นี่คือฟังก์ชั่นที่คาดหวัง หากคุณต้องการเห็นผลลัพธ์จากนั้นให้รันมันในเทอร์มินัลด้วยตนเองหรือตั้งค่าการรอที่ส่วนท้ายของโปรแกรมเพื่อให้เปิดอยู่สักครู่หนึ่ง (โดยใช้ไลบรารีเธรด)


0

นี่คือคำตอบasync ที่แอพคอนโซลใน C #?

อะไรที่ใดก็ตามใน app คอนโซลไม่เคยใช้awaitแต่แทนที่จะใช้theAsyncMethod().GetAwaiter().GetResult();,

ตัวอย่าง

var result = await HttpClientInstance.SendAsync(message);

กลายเป็น

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


-3

หากโปรแกรมของคุณต้องการให้คุณกด Enter เพื่อดำเนินการต่อเหมือนที่คุณต้องป้อนค่าและดำเนินการต่อจากนั้นเพิ่ม double หรือ int ใหม่แล้วพิมพ์ write ก่อน retunr (0); scanf_s ("% lf", & ตัวแปร);


1
นี่คือคำถามC #
Wai Ha Lee

-3

ฉันมักจะเพิ่มคำสั่งต่อไปนี้ไปยังแอปพลิเคชันคอนโซล (สร้างข้อมูลโค้ดสำหรับสิ่งนี้หากคุณต้องการ)

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

การทำเช่นนี้จะช่วยเมื่อคุณต้องการทดสอบแนวคิดที่แตกต่างผ่านแอปพลิเคชันคอนโซล

Ctr + F5จะทำให้อยู่ในคอนโซล แต่คุณไม่สามารถดีบักได้! แอปพลิเคชั่นคอนโซลทั้งหมดที่ฉันเขียนในโลกแห่งความจริงนั้นไม่ได้มีการโต้ตอบและถูกกระตุ้นโดย Scheduler เช่น TWS หรือ CA Work station และไม่ต้องการอะไรแบบนี้


-3

เพื่อทำให้สิ่งที่ผู้อื่นพูดง่ายขึ้น: ใช้ Console.ReadKey();การใช้งาน

สิ่งนี้ทำให้โปรแกรมกำลังรอให้ผู้ใช้กดปุ่มปกติบนแป้นพิมพ์

ที่มา: ฉันใช้มันในโปรแกรมของฉันสำหรับแอปพลิเคชันคอนโซล


-3

คุณสามารถแก้ไขได้อย่างง่าย ๆ เพียงแค่เรียกใช้อินพุต อย่างไรก็ตามหากคุณกดEnterจากนั้นคอนโซลจะหายไปอีกครั้ง เพียงใช้สิ่งนี้Console.ReadLine();หรือConsole.Read();


-4

เพิ่มต่อไปนี้ก่อนที่จะส่งคืน 0:

system("PAUSE");  

พิมพ์บรรทัดเพื่อกดปุ่มเพื่อปิดหน้าต่าง มันจะทำให้หน้าต่างขึ้นจนกว่าคุณจะกดปุ่ม Enter ฉันให้นักเรียนเพิ่มลงในโปรแกรมทั้งหมดของพวกเขา


1
นั่นคือใน c ++
Gonçalo Garrido

-13

ตามความกังวลของฉันถ้าเราต้องการเสถียรภาพเอาท์พุทของแอปพลิเคชั่นคอนโซลจนถึงการปิดการแสดงผลการใช้งานฉลาก: หลังจาก MainMethod และ goto label; ก่อนสิ้นสุดโปรแกรม

ในโปรแกรม

เช่น:

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

    // Snippet of code

    goto label;
}

2
นี่จะทำให้โปรแกรมโปสเตอร์พิมพ์ "Hello, World!" ต่อไป หลายครั้ง
DavidPostill

1
พระเยซูคริสต์ไม่ทราบว่ามีgotoข้อความอนุญาตแม้แต่ใน C #
Ch3shire
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.