繁体   English   中英

C#:根据用户输入创建字符串数组,然后,如果无法将其解析为int数组,请重试输入

[英]C#: Creating a string array from user input, then if it can't be parsed into int array, retrying the input

我一直在尝试使用C#制作矩阵控制台应用程序,但是在检查用户输入的可行性时,我一直很努力。 这是代码:

//INPUT OF VALUES INTO MATRIX A BY ROWS
int ValuesCounter = 2; //index for new arrays created on fail.
string[] valuesValuesCounter = Console.ReadLine().Split(' '); //read user input into string array
int[] valuescheckValuesCounter = new int[valuesValuesCounter.Length]; //test array to check if user input can be parsed into int
for (int i = 0; i <= valuesValuesCounter.Length; i++) // loop for checking parseability of individual array items
{
    while(!int.TryParse(valuesValuesCounter[i], out valuescheckValuesCounter[i])) //same
    {
        /*if it can't be parsed, create new array and try again*/
        ValuesCounter += 2;
        Console.WriteLine("Wrong values! Please try again!");
        valuesValuesCounter = Console.ReadLine().Split(' ');
        valuescheckValuesCounter = new int[valuesValuesCounter.Length];
    }
}

我怀疑这是非常有效的。 我尝试使用ArrayList代替,因为您只能删除其中的值,但是无法拆分,因此我不知道如何使其工作。 有什么更好的方法可以做到这一点?
还尝试进行自己的研究,但没有找到任何解决方案(也许它在那里,我只是因为没有看到它而愚蠢,我不知道)。

如何在C#中删除数组?
将2D字符串数组转换为2D int数组(多维数组)
C#arraylist用户输入
int.TryParse解析为一个对象数组 (这看起来很接近,但是我看不到有任何东西可以重试输入以防无法解析)。

所以你有它。 我很傻,所以如果这个问题看起来很愚蠢,那是因为问这个问题的那个愚蠢的人。

首先,使用户体验尽可能好。 一次输入矩阵容易出错,使用户的生活更加轻松并逐步进行。

第二,制作执行简单任务的小型方法。 如果出现新的要求,它们就更容易推理,更容易编写,更容易调试和更容易修改。 不要让方法做太多事情,它只会给您带来头痛,并且会花费不必要的调试时间。 如果您正在学习,请不要担心似乎正在分解为看似荒谬的简单任务,您不会后悔。 永远记住,您能想象到的最复杂的问题总是可以解决较小更简单的问题。

因此,您需要的第一件事是一种提示用户输入有效整数的方法,因此让我们尝试一下:

private static int GetIntegerFromUser(string prompt)
{
    int value;
    Console.Write($"{prompt}: ");

    while (!int.TryParse(Console.ReadLine(), out value))
    {
        Console.WriteLine("That is not a valid value. Please try again.");
        Console.Write($"{prompt}: ");
    }

    return value;
}

看看如何运作? 这种方法在生活中有一个目标。 让用户输入有效的整数。 不必介意整数是什么,它不在乎,那不是它的工作,这种方法将不断询问用户,直到实现其生活目标为止。

好的,接下来是什么? 填写矩阵时,我们需要知道:

  1. 行数
  2. 列数
  3. 价值观

好吧,让我们写一些方法来获取:

private static (int Rows, int Columns) GetMatrixSize()
{
    var rows = GetIntegerFromUser("Please enter number of rows");
    var columns = GetIntegerFromUser("Please enter number of columns");
    return (rows, columns);
}

和,

private static int[,] GetMatrixValues(int rows, int columns)
{
    var matrix = new int[rows, columns];

    for (var row = 0; row < rows; row++)
    {
        for (var column = 0; column < columns; column++)
        {
            matrix[row, column] =
               GetIntegerFromUser($"Enter matrix value [{row}, {column}]");
        }
    }
}

现在您应该意识到为什么制作执行简单任务的小型方法是一个好主意的原因。 因为机会真的很好,所以您将可以重用它们,一旦您知道该方法正确运行,它便会在任何地方正确运行。

好的,我们已经有了所有需要的东西,现在只需将它们放在一起即可:

public static int[,] GetMatrixFromUser()
{
    var size = GetMatrixSize();
    return GetMatrixValues(size.Rows, size.Columns);
}

读起来有多容易?

至此,我们完成了! 真? 好吧 我们根本没有价值验证,这可能是一个问题。 如果有人决定输入负数行会怎样? 好的,没问题,让我们建立一个确保值在有效范围内的方法:

private static bool IsInRange(int value, 
                              int lowerInclusiveBound,
                              int upperExclusiveBound,
                              string messageOnFailedValidation)
{
    if (value >= lowerInclusiveBound &&
        value < upperExclusiveBound)
        return true;

    Console.WriteLine(messageOnFailedValidation);
    return false;
}

现在,由于我们使用了可以很好地完成定义任务的小型方法,因此添加新要求很容易就可以对GetMatrixSize方法进行一些修改:

private static (int Rows, int Columns) GetMatrixSize()
{
    int rows, columns;

    do
    {
        rows = GetIntegerFromUser("Please enter number of rows");
        columns = GetIntegerFromUser("Please enter number of columns");
    } while (!IsInRange(rows,
                        1,
                        int.MaxValue,
                        "Number of rows must be equal or greater than one.") |
             !IsInRange(columns,
                        1,
                        int.MaxValue,
                        "Number of columns must be equal or greater than one."));

    return (rows, columns);
}

是的,现在我们完成了...

几乎! 最后一件事。 另一个好习惯是确保您所相信的事实是真实的。 您认为GetMatrixValues内部的GetMatrixValues什么? 您认为rowscolumns将具有有效值。 但是您的信念纯粹基于信念,您没有检查这是否是真的。

但是等等...我已经签入GetMatrixSize吗? 是的,但是您如何保证GetMatrixValues不会再通过其他方法调用GetMatrixValues 可重用性还记得吗?

在这里,您可以走两条路。 如果值无效或可以断言这些值实际上有效,则可以引发异常。 由于该方法是私有的,并且具有无效值,可能意味着在调用堆栈中的某个地方存在错误,因此,更好的选择是声明您的真相:

private static int[,] GetMatrixValues(int rows, int columns)
{
    Debug.Assert(rows > 0 && columns > 0);
    var matrix = ...
}

还有其他关于信仰的真理吗? 谁是确保upperExclusiveBoundlowerInclusiveBoundIsInRange实际意义? 是否有人阻止您拨打以下电话: IsInRange(10, 100, -100, ...) 这样的调用可能是代码中其他地方的错误,通过使这类错误更容易发现,可以使您的生活更轻松。 再次声明您的事实:

private static bool IsInRange(int value, 
                              int lowerInclusiveBound,
                              int upperExclusiveBound,
                              string messageOnFailedValidation)
{  
    Debug.Assert(upperExclusiveBound > lowerInclusiveBound);

    if ...
}  

一个很好的例子也可以由上无论您应检查promptGetIntegerFromUsermessageOnFailedValidationIsInRange不为空或空字符串,等等。

是的,现在我们真的完成了。

您不需要for循环内的while循环。 只需检查每个项目的有效性和中断,如果遇到无效的字符串,当然,如果所有的字符串都是有效的(循环将结束),并且i等于数组的长度:

bool success = false;
do
{
     int i = 0;
     string[] valuesValuesCounter = Console.ReadLine().Split(' ');
     int[] valuescheckValuesCounter = new int[valuesValuesCounter.Length];
     for (int i = 0; i <= valuesValuesCounter.Length; i++)
        if(!int.TryParse(valuesValuesCounter[i], out valuescheckValuesCounter[i]) break;
     success = i == valuesValuesCounter.Length;
}while(!success);

另一种方法是使用Linq:

do
{
    int i = 0;
    string[] valuesValuesCounter = Console.ReadLine().Split(' ');
    int[] valuescheckValuesCounter = new int[valuesValuesCounter.Length];
    success = valuesValuesCounter.All(x => int.TryParse(x, out valuescheckValuesCounter[i++]);
}while(!success);

暂无
暂无

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

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