【问题标题】:How do I stop c# from crashing when user input is a string and its supposed to be an integer with int.tryparse?当用户输入是字符串并且它应该是 int.tryparse 的整数时,如何阻止 c# 崩溃?
【发布时间】:2021-12-12 18:25:37
【问题描述】:

我想学习如何在我的代码中实现 int.tryparse 命令,以防止程序因输入无效而崩溃。这是我到目前为止所写的:

using System;

namespace barn_
{
    class Program
    {

        static void Main(string[] args)
        {
            int age;
            string a;

            do
            {
                Console.WriteLine("How old is the person?");
                age = Convert.ToInt32(Console.ReadLine());
                a = Convert.ToString(Console.ReadLine());

                bool v = int.TryParse(a, out age);
                while(a == true)
                {
                    Console.WriteLine("");
                    Console.WriteLine("");
                }
                if (age >= 2 && age <= 5)
                {
                    Console.ForegroundColor = ConsoleColor.Blue;
                    Console.WriteLine("The person has blue clothes.");
                }
                else if (age >= 6 && age <= 9 || age >= 10 && age <= 15)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("The person has red clothes.");
                }
                else if (age < 2)
                {
                    Console.WriteLine("The person is too young.");
                    Console.WriteLine();
                }
                else if (age > 15)
                {
                    Console.WriteLine("The person is too old.");
                    Console.WriteLine();
                }
            } while (age < 2 || age > 15);
        }
    }
}

【问题讨论】:

  • 你确定它在 bool v = int.TryParse(a, out age); 上崩溃了吗?声明而不是年龄 = Convert.ToInt32(Console.ReadLine());?是否有异常写入控制台或系统的事件查看器,您可以发布?
  • 您遇到的另一个问题是 while 循环 while(a == true)... 这永远不会退出。使用 try / catch 确保输入有效。
  • a = Convert.ToString(Console.ReadLine()); bool v = int.TryParse(a, out age); 为什么需要这两行?
  • 我对@9​​87654325@ 的用途感到非常困惑。如果该变量实际上有一个有意义的名称可能会有所帮助,但即便如此,我还是不明白这一点。与v 类似。您的变量应具有描述性名称。
  • 我在代码中没有异常。您在帖子中看到的是代码。我需要年龄 = Convert.ToInt32(Console.ReadLine());语句,以便用户实际上可以输入一个整数。它不会在 v = int.TryParse(a, out age); 上崩溃据我所知的声明。只有当用户用文本或十进制数字对问题 Console.WriteLine("How old is the person?"); 做出响应时,它才会崩溃;在控制台中。 @spyder1329

标签: c# string input error-handling integer


【解决方案1】:

您可以提取一个方法来读取整数值:

private static int ReadInteger(string title, int from, int to) {
  // Keep asking user until some valid input is provided 
  while (true) {
    // If we have a title, print it
    if (!string.IsNullOrWhiteSpace(title))
      Console.WriteLine(title);

    // First we try to parse user input 
    if (int.TryParse(Console.ReadLine(), out int result)) 
      // if parsing succeeds, check for ranges
      if (result >= from && result <= to)
        return result; // result is a valid value in [from..to] range
      else // valid integer, but out of [from..to] range, say, 12345 or -97
        Console.WriteLine($"Value is out of [{from}..{to}] range. Please, try again.");
    else // not a valid integer, say, "bla-bla-bla"
      Console.WriteLine("Not a valid integer value. Please, try again.");
  }
}

那么你可以使用这个方法如下:

static void Main(string[] args) {
  // we read and integer, say, in [0..122] range
  // https://en.wikipedia.org/wiki/Jeanne_Calment
  int age = ReadInteger("How old is the person?", 0, 122);

  // try to order the conditions: when ordered they are more readable 
  if (age < 2)
    Console.WriteLine("The person is too young.");
  else if (age <= 5) {
    Console.ForegroundColor = ConsoleColor.Blue;
    Console.WriteLine("The person has blue clothes.");
  }
  else if (age <= 15) { 
    Console.ForegroundColor = ConsoleColor.Red;
    Console.WriteLine("The person has red clothes.");
  }
  else
    Console.WriteLine("The person is too old.");
}

【讨论】:

  • 这种方法效果很好,只是让我理解一切变得复杂,因为我只有 1 个月的时间开始编码。
【解决方案2】:

通过下面的回答,我会尽量避免可能的坏习惯。对于大多数用例,我的代码示例可能被夸大了,但我想澄清几点并解释面向对象编程中可重用性的各个方面。 但是,@Dmitry Bychenko 的回答和对您问题的 cmets 可以高度确定地解决您所描述的问题。

根据您正在开发的 IDE(例如 Visual Studio 2019),记录良好的方法(大多数系统方法(例如 int.TryParseConvert.ToInt32)都是这种情况)将向您显示可能发生的异常。 例如,int.TryParse 如果没有输入整数,则不会引发异常。这与Convert.ToInt32 不同。如果尝试用Convert.ToInt32转换非整数的字符串,则会抛出异常FormatException,表示要转换的部分不是整数。

现在来看代码示例和可重用性。 您示例的以下两个代码 sn-ps 非常相似。这主要可以从可以从中生成方法的事实中推断出来。在 Visual Studio 2019 中,可以使用“Ctrl + R + M”创建自动生成的方法。

Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("The person has blue clothes.");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("The person has red clothes.");

在后面的代码示例中,此方法的名称为“PrintTextInConsoleInColor”。使用方法的充分理由是设置颜色并打印文本。这种模式会重复。如果要在每次设置颜色时输出声音,则必须更改代码出现的每个部分。这是非常糟糕的,需要付出很多努力,甚至不一致。这对于大型项目来说是非常严重和耗时的,当然对于比设置颜色和播放声音更复杂的过程来说,这只是为了演示。

方法的命名也起着重要的作用。人们不得不认为它不仅仅是控制台输入。这就是为什么“GetIntegerFromConsoleInput”这个名字在纯控制台应用程序的上下文中被夸大了,尽管它应该总是从方法的名称中清楚地知道内部发生了什么或调用它时,所以当它被执行时你不会突然感到惊讶.

在可重用性方面,将您想要的逻辑拆分为几个部分是有意义的,例如“GetIntegerFromConsoleInput”和“GetIntegerInRangeFromConsoleInput”。这样做的原因是,如果您只需要一个数字,可以使用“GetIntegerFromConsoleInput”方法。但是,如果您需要一个范围内的数字,如您的情况,将使用“GetIntegerInRangeFromConsoleInput”。 如果您现在查看该方法的文档,您可以看到异常的文档,它也被“Visual Studio”之类的 IDE 应用。 基本上,还建议避免嵌套“if 语句”和“循环”,因为这会严重影响代码的可读性。 在Console中,可以通过控制字符插入空行,省去了“Console.WriteLine("")”的多次使用。

Console.WriteLine("Hello\nWorld");

最后,为 ConsoleIO 编写一个类以及如何重用它的潜在解决方案。

public class ConsoleIOHelper
{
    /// <summary>
    /// Get console input within range.
    /// </summary>
    /// <param name="lowerBoundary"> Lower boundary included in Range.</param>
    /// <param name="upperBoundary"> Upper boundary included in Range.</param>
    /// <exception cref="ArgumentOutOfRangeException">Thrown in case the lower boundary is greater than the upper boundary.</exception>
    public int GetIntegerInRangeFromConsoleInput(int lowerBoundary, int upperBoundary)
    {
        if (lowerBoundary >= upperBoundary)
        {
            throw new ArgumentOutOfRangeException(nameof(lowerBoundary), "Lower boundary has to be lower than upper boundary!");
        }

        int result;
        bool isInRange;

        do
        {
            result = GetIntegerFromConsoleInput();
            isInRange = IsInBoundaries(result, lowerBoundary, upperBoundary);

            if (!isInRange)
            {
                PrintTextInConsoleInColor($"Input {result} is not within boundaries of {lowerBoundary} and {upperBoundary}", ConsoleColor.Red);
            }
        }
        while (!isInRange);

        return result;
    }

    /// <summary>
    /// Get interger from console input.
    /// </summary>
    public int GetIntegerFromConsoleInput()
    {
        bool isInteger;
        int result;

        do
        {
            isInteger = int.TryParse(Console.ReadLine(), out result);

            if (!isInteger)
            {
                PrintTextInConsoleInColor("Input is not a number!", ConsoleColor.Red);
            }
        }
        while (!isInteger);

        return result;
    }

    /// <summary>
    /// Checks weather a input number is within lower and upper boundary.
    /// </summary>
    private bool IsInBoundaries(int input, int lowerBoundary, int upperBoundary)
    {
        return input >= lowerBoundary && input <= upperBoundary;
    }

    private void PrintTextInConsoleInColor(string message, ConsoleColor consoleColor)
    {
        Console.ForegroundColor = consoleColor;
        Console.WriteLine(message);
        Console.ResetColor();
    }
}

我希望我能够让您的问题更加清晰,即使我与实际问题有很大的偏差。如果我描述了已经知道的事情,我深表歉意,我只是想用这个例子来指出让我印象深刻的事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-09
    • 2015-12-09
    • 2015-12-16
    相关资源
    最近更新 更多