【问题标题】:How to set default input value in .Net Console App?如何在 .Net Console App 中设置默认输入值?
【发布时间】:2010-12-11 22:28:50
【问题描述】:

如何在 .net 控制台应用程序中设置默认输入值?

这是一些虚构的代码:

Console.Write("Enter weekly cost: ");
string input = Console.ReadLine("135"); // 135 is the default. The user can change or press enter to accept
decimal weeklyCost = decimal.Parse(input);

当然,我没想到会这么简单。我打赌必须做一些低级的、不受管理的事情;我只是不知道怎么做。

编辑

我知道我可以将 no input 替换为默认值。这不是我要问的。我正在尝试了解实现我所描述的行为所涉及的内容:为用户提供可编辑的默认值。我也不担心输入验证;我的问题与此无关。

【问题讨论】:

  • 您可以按照建议的答案对其进行编码 - 用户不会关心编码技术。对于理论上的问题,如果有办法用 readline 做到这一点 - 可能没有(至少没有记录)。
  • 但是 - 我知道你想离开,我们正在寻找一种解决方案,使用户能够更改默认文本。
  • 我知道它不能用 .ReadLine() 来完成。但是,我知道有办法做到这一点。

标签: c# .net input console console-application


【解决方案1】:

我相信您将通过聆听每次按键来手动管理此操作:

快速拼凑示例:

   // write the initial buffer
   char[] buffer = "Initial text".ToCharArray();
   Console.WriteLine(buffer);

   // ensure the cursor starts off on the line of the text by moving it up one line
   Console.SetCursorPosition(Console.CursorLeft + buffer.Length, Console.CursorTop - 1);

   // process the key presses in a loop until the user presses enter
   // (this might need to be a bit more sophisticated - what about escape?)
   ConsoleKeyInfo keyInfo = Console.ReadKey(true);
   while (keyInfo.Key != ConsoleKey.Enter)
   {

       switch (keyInfo.Key)
       {
            case ConsoleKey.LeftArrow:
                    ...
              // process the left key by moving the cursor position
              // need to keep track of the position in the buffer

         // if the user presses another key then update the text in our buffer
         // and draw the character on the screen

         // there are lots of cases that would need to be processed (backspace, delete etc)
       }
       keyInfo = Console.ReadKey(true);
   }

这非常复杂 - 您必须确保光标不会超出范围并手动更新缓冲区。

【讨论】:

  • 我不认为这就是问题的意思。
  • 其实这绝对是目前为止最好的答案。
  • 把它放到一个扩展方法中,这样你就可以调用 Console.ReadLine("135");扩展方法可以是现有方法的重载吗?如果没有,请给它一个新名称。
  • @Dennis - 你不能向静态类添加扩展方法,因为你不能创建它们的实例。也许 SuperConsole.ReadLine("default")?有很多情况需要处理,但将其编码并打包成 DLL 应该是值得的。
  • 当我尝试为控制台创建扩展方法时,我得到“静态类型不能用作参数”。所以也许这行不通,也许这是一个新的 SO 问题。
【解决方案2】:

这是一个简单的解决方案:

public static string ConsoleReadLineWithDefault(string defaultValue)
{
    System.Windows.Forms.SendKeys.SendWait(defaultValue);
    return Console.ReadLine();
}

然而,它并不完整。 SendWait 输入字符串中的某些字符具有特殊含义,因此您必须将它们转义(例如 +、(、) 等) 有关完整说明,请参阅:http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.aspx

【讨论】:

    【解决方案3】:

    我继续完成了 Matt 的实现方法:

        public static string ReadInputWithDefault(string defaultValue, string caret = "> ")
        {
            Console.WriteLine(); // make sure we're on a fresh line
    
            List<char> buffer = defaultValue.ToCharArray().Take(Console.WindowWidth - caret.Length - 1).ToList();
            Console.Write(caret); 
            Console.Write(buffer.ToArray());
            Console.SetCursorPosition(Console.CursorLeft, Console.CursorTop);
    
            ConsoleKeyInfo keyInfo = Console.ReadKey(true);
            while (keyInfo.Key != ConsoleKey.Enter)
            {
                switch (keyInfo.Key)
                {
                    case ConsoleKey.LeftArrow:
                        Console.SetCursorPosition(Math.Max(Console.CursorLeft - 1, caret.Length), Console.CursorTop);
                        break;
                    case ConsoleKey.RightArrow:
                        Console.SetCursorPosition(Math.Min(Console.CursorLeft + 1, caret.Length + buffer.Count), Console.CursorTop);
                        break;
                    case ConsoleKey.Home:
                        Console.SetCursorPosition(caret.Length, Console.CursorTop);
                        break;
                    case ConsoleKey.End:
                        Console.SetCursorPosition(caret.Length + buffer.Count, Console.CursorTop);
                        break;
                    case ConsoleKey.Backspace:
                        if (Console.CursorLeft <= caret.Length)
                        {
                            break;
                        }
                        var cursorColumnAfterBackspace = Math.Max(Console.CursorLeft - 1, caret.Length);
                        buffer.RemoveAt(Console.CursorLeft - caret.Length - 1);
                        RewriteLine(caret, buffer);
                        Console.SetCursorPosition(cursorColumnAfterBackspace, Console.CursorTop);
                        break;
                    case ConsoleKey.Delete:
                        if (Console.CursorLeft >= caret.Length + buffer.Count)
                        {
                            break;
                        }
                        var cursorColumnAfterDelete = Console.CursorLeft;
                        buffer.RemoveAt(Console.CursorLeft - caret.Length);
                        RewriteLine(caret, buffer);
                        Console.SetCursorPosition(cursorColumnAfterDelete, Console.CursorTop);
                        break;
                    default:
                        var character = keyInfo.KeyChar;
                        if (character < 32) // not a printable chars
                            break;
                        var cursorAfterNewChar = Console.CursorLeft + 1;
                        if (cursorAfterNewChar > Console.WindowWidth || caret.Length + buffer.Count >= Console.WindowWidth - 1)
                        {
                            break; // currently only one line of input is supported
                        }
                        buffer.Insert(Console.CursorLeft - caret.Length, character);
                        RewriteLine(caret, buffer);
                        Console.SetCursorPosition(cursorAfterNewChar, Console.CursorTop);
                        break;
                }
                keyInfo = Console.ReadKey(true);
            }
            Console.Write(Environment.NewLine);
    
            return new string(buffer.ToArray());
        }
    
        private static void RewriteLine(string caret, List<char> buffer)
        {
            Console.SetCursorPosition(0, Console.CursorTop);
            Console.Write(new string(' ', Console.WindowWidth - 1));
            Console.SetCursorPosition(0, Console.CursorTop);
            Console.Write(caret);
            Console.Write(buffer.ToArray());
        }
    

    注意事项:

    • 仅适用于一行输入
    • 您可以定义可编辑文本区域之前的内容(caret 参数)
    • 使用风险自负,可能仍然存在一些 IndexOutOfBound 问题。 ;)

    【讨论】:

      【解决方案4】:

      或者...只测试输入的值,如果它是空的,输入默认值。

      【讨论】:

        【解决方案5】:
        1. 在您的项目中添加对程序集库“System.Windows.Forms”的引用
        2. 在 Console.WriteLine 命令之后和 Console.ReadLine 命令之前立即添加 SendKeys.SendWait("DefaultText")

         

        string _weeklycost = "";
        Console.WriteLine("Enter weekly cost: ");
        System.Windows.Forms.SendKeys.SendWait("135");
        _weeklycost = Console.ReadLine();
        

        【讨论】:

          【解决方案6】:

          现在有更好的方法可以做到这一点,请查看 nuget 上的 Readlinehttps://www.nuget.org/packages/ReadLine

          1. install-package Readline
          2. var input = ReadLine.Read("Enter weekly cost: ", "135");

          我喜欢使用控制台来编写交互式测试,使用默认值真的很有帮助。

          【讨论】:

          • 这里略有不同:@default 只是一个默认值,而不是一个可以被用户删除的自动插入值
          • 一个很好的框架可以使用...但只有 .net 标准 2.0...不适用于 .net 框架...使用 .net 框架我在尝试安装该软件包时遇到错误
          • 对不起。我的陈述有误。我发现,我至少需要 .NET Framework 4.6.1,但在我的项目中我使用的是 4.5.2。这就是为什么我不能使用那个库/nuget-package 的原因。
          【解决方案7】:

          简单的解决方案,如果用户什么都不输入,分配默认值:

          Console.Write("Enter weekly cost: ");
          string input = Console.ReadLine();
          decimal weeklyCost = String.IsNullOrEmpty(input) ? 135 : decimal.Parse(input);
          

          在处理用户输入时,您应该预料到它可能包含错误。因此,如果用户没有输入数字,您可以使用 TryParse 来避免异常:

          Console.Write("Enter weekly cost: ");
          string input = Console.ReadLine(); 
          decimal weeklyCost;
          if ( !Decimal.TryParse(input, out weeklyCost) ) 
              weeklyCost = 135;
          

          这将被视为处理用户输入的最佳实践。如果您需要解析许多用户输入,请为此使用辅助函数。一种方法是使用一个可以为 null 的方法,如果解析失败则返回 null。然后很容易使用null coalescing operator 分配默认值:

          public static class SafeConvert
          {
              public static decimal? ToDecimal(string value)
              {
                  decimal d;
                  if (!Decimal.TryParse(value, out d))
                      return null;
                  return d;
              }
          }
          

          然后,读取输入并分配默认值很简单:

          decimal d = SafeConvert.ToDecimal(Console.ReadLine()) ?? 135;
          

          【讨论】:

          • 你把他的虚拟参数留给了ReadLine
          【解决方案8】:

          你可以像这样使用辅助方法:

          public static string ReadWithDefaults(string defaultValue)
          {
              string str = Console.ReadLine();
              return String.IsNullOrEmpty(str) ? defaultValue : str;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-11-14
            • 1970-01-01
            • 1970-01-01
            • 2015-11-02
            • 1970-01-01
            相关资源
            最近更新 更多