0

を呼び出しConsole.ReadKey()、プロンプトで長さ > 1 のクリップボード テキストを貼り付けます (「Hello World!」としましょう)。

予期せず、Console.ReadKey() への後続の呼び出しで、ユーザーにプロンプ​​トを表示する代わりに、プロンプトが表示されないことを発見しました! 代わりに、貼り付けられたテキストの後続の文字が読み取られます...プロンプトは表示されません!

結論: ReadKey を使用するには、次に ReadKey を呼び出すときに、実際にユーザーにプロンプ​​トが表示されるようにする必要があります。現在、これにより ReadKey はこのような重大なシナリオでは使用できなくなります。

これを無効にする方法や、入力されたがまだ読み取られていない値を単純にクリアする方法はないようです。

私の場合、単純なコンソール アプリに重大なエラーが表示され、「RUN」を表す「R」、または「END」を表す「E」を探してループしていました。この間近にファイル パスの入力を求めるプロンプトが表示されるので、既に使用しているユーザーがこの時点で誤ってファイル パスを貼り付けるのはかなり簡単でした。問題は (!!!)、そのファイル パスに「r」が含まれている場合、すぐに実行されます。

using System;

namespace Practise1
{
    class Program
    {
        static void Main()
        {
            RunDialogue2();
        }

        public static void RunDialogue()
        {
            while (true) {
                Console.WriteLine("Type 'R' to RUN, 'E' to END");
                ConsoleKey key = Console.ReadKey().Key;
                Console.WriteLine("\r\n");

                switch (key) {
                    case ConsoleKey.R:
                        Console.WriteLine("RUN! ENGINES BLAST OFF!");
                        BlastOff();
                        break;
                    case ConsoleKey.E:
                        Console.WriteLine("FINISHED");
                        return;
                    default:
                        Console.WriteLine("INVALID ENTRY, TRY AGAIN");
                        // we *thought* this would pick up bad input, but not pasted text!
                        break;
                }
            }

        }

        public static void RunDialogue2()
        {
            while (true) {
                Console.WriteLine("Type 'R' to RUN, 'E' to END");
                ConsoleKey key = Console.ReadKey().Key;
                Console.WriteLine("\r\n");

                switch (key) {
                    case ConsoleKey.R:
                        Console.WriteLine("RUN! ENGINES BLAST OFF!");
                        Console.WriteLine("We blasted off at: " + DateTime.UtcNow);
                        //BlastOff();
                        break;
                    case ConsoleKey.E:
                        Console.WriteLine("FINISHED");
                        return;
                    default:
                        Console.WriteLine("INVALID ENTRY, TRY AGAIN");
                        // we *thought* this would pick up bad input, but not pasted text!
                        break;
                }
            }
        }
    }
}

あなたが「チャーリーの!」を持っていたら!クリップボードに貼り付けて、ここに出力があります。複数の RUN を取得する方法に注目してください。すべて意図しない。これがどれほど悪いかは非常に恐ろしいことです。これは、特に入力を検証していると思った場合に、実現可能な入力メソッドとして ReadKey に決して依存できないことを意味します。

Type 'R' to RUN, 'E' to END
C

INVALID ENTRY, TRY AGAIN
Type 'R' to RUN, 'E' to END
h

INVALID ENTRY, TRY AGAIN
Type 'R' to RUN, 'E' to END
a

INVALID ENTRY, TRY AGAIN
Type 'R' to RUN, 'E' to END
r

RUN! ENGINES BLAST OFF!
We blasted off at: 7/21/2013 11:24:36 PM
Type 'R' to RUN, 'E' to END
l

INVALID ENTRY, TRY AGAIN
Type 'R' to RUN, 'E' to END
e

FINISHED

代わりに Console.ReadLine を使用することで解決できることはわかっていますが、キーを 1 回押すだけですぐに対話できる機能は、はるかに満足のいくものでした。この奇妙な動作を回避する方法はありますか?

4

2 に答える 2

2

次のようなものは、readkey による一定の読み取りを取り除きます。

    public static void RunDialogue()
    {
        while (true)
        {
            Console.WriteLine("Type 'R' to RUN, 'E' to END");
            ConsoleKey key = Console.ReadKey().Key;
            Console.WriteLine("\r\n");
            switch (key)
            {
                case ConsoleKey.R:
                    Console.WriteLine("RUN! ENGINES BLAST OFF!");
                    BlastOff();
                    break;
                case ConsoleKey.E:
                    Console.WriteLine("FINISHED");
                    return;
                default:
                    Console.WriteLine("INVALID ENTRY, TRY AGAIN");
                    // we *thought* this would pick up bad input, but not pasted text!
                    break;
            }
            Console.In.ReadToEnd();
        }

    }

これにより、元の投稿の差し迫った問題は解消されますが、より完全な解決策は、入力ストリームの残りを読み取り、画面にエコーせずに無視することです。次のような方法が機能します。

    public static void RunDialogue()
    {
        while (true)
        {
            Console.WriteLine("Type 'R' to RUN, 'E' to END");
            ConsoleKey key = Console.ReadKey().Key;
            Console.WriteLine("\r\n");
            switch (key)
            {
                case ConsoleKey.R:
                    Console.WriteLine("RUN! ENGINES BLAST OFF!");
                    BlastOff();
                    break;
                case ConsoleKey.E:
                    Console.WriteLine("FINISHED");
                    return;
                default:
                    Console.WriteLine("INVALID ENTRY, TRY AGAIN");
                    // we *thought* this would pick up bad input, but not pasted text!
                    break;
            }
            while (Console.KeyAvailable)
            {
                Console.ReadKey(true);
            }
        }

    }
于 2013-07-21T23:37:30.563 に答える
0

をチェックして重要な解決策を明らかにした@tinstaaflの回答に感謝しますConsole.KeyAvailable。私は間違いなく公平にその答えを解決策として残していますが、以下は、入力が本当に単一の文字であることを完全に確認する必要があるシナリオをカバーする最終的な解決策です。

        public static ConsoleKey ReadKeySingle(bool intercept = false, ConsoleKey errorKey = ConsoleKey.Clear)
        {
            ConsoleKey key = Console.ReadKey(intercept).Key;
            while (Console.KeyAvailable) {
                Console.ReadKey(true);
                key = errorKey;
            }
            return key;
        }

次に、次のように使用します(1行の変更):

        public static void RunDialogue()
        {
            while (true) {
                Console.WriteLine("Type 'R' to RUN, 'E' to END");

                // KEY! Call ReadKeySingle instead
                ConsoleKey key = ReadKeySingle(); // Console.ReadKey().Key; //!!!

                Console.WriteLine("\r\n");

                switch (key) {
                    case ConsoleKey.R:
                        Console.WriteLine("RUN! ENGINES BLAST OFF!");
                        Console.WriteLine("We blasted off at: " + DateTime.UtcNow);

                        // BlastOff();
                        break;
                    case ConsoleKey.E:
                        Console.WriteLine("FINISHED");
                        return;
                    default:
                        Console.WriteLine("INVALID ENTRY, TRY AGAIN");
                        // we *thought* this would pick up bad input, but not pasted text!
                        break;
                }
            }
        }
于 2013-07-22T00:20:50.130 に答える