0

调用Console.ReadKey()并在提示符处对长度 > 1 的任何剪贴板文本进行粘贴(编辑->粘贴)(比如说“Hello World!”)。

我刚刚意外地发现,在随后调用 Console.ReadKey() 时,向用户显示提示,却没有给出提示!相反,粘贴文本中的后续字符会被读取......没有提示!

底线:要使用 ReadKey,我需要确保(非常确定)当我下次调用 ReadKey 时,它实际上会给用户一个提示。目前,这使得 ReadKey 无法用于此类关键场景。

看起来没有任何方法可以禁用此功能,或者只是清除输入但尚未读出的值。

就我而言,这在简单的控制台应用程序中出现了严重错误,我在其中循环寻找“RUN”的单词“R”或任何“E”到“END”。由于接近这个时间,我提示输入文件路径,因此对于已经使用它的用户来说,在这一点上意外粘贴文件路径是相当容易的。问题是(!!!),如果该文件路径包含“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,但是通过单次按键立即交互的能力要快乐得多。有什么办法可以解决这种奇怪的行为吗?

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

然后像这样使用它(单行更改):

        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 回答