繁体   English   中英

当用户输入是一个字符串并且它应该是一个带有 int.tryparse 的整数时,如何阻止 c# 崩溃?

[英]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 命令,以防止程序因无效输入而崩溃。 这是我到目前为止所写的:

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

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

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.");
}

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

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

现在来看代码示例和可重用性。 您示例的以下两个代码片段非常相似。 这主要可以从可以从它们中生成方法的事实中推断出来。 在 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();
    }
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM