当我们试图在字符串变量中输入字符以外的任何内容时,如何处理C#中的字符串异常

本文关键字:字符串 何处理 异常 处理 任何内 我们 变量 输入 字符 | 更新日期: 2023-09-27 18:29:46

就像我想展示的那样,在类中输入itemname的值。然后,当有人输入字母以外的其他内容时,如何处理异常。为什么不起作用?

try
{
    Console.WriteLine("Please Enter the Item Name");
    item1.itemname = Console.ReadLine();
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
    Console.Write("Please enter Name in the Correct Format");
    if (e.Message != null)
        z = 1;
}

当我们试图在字符串变量中输入字符以外的任何内容时,如何处理C#中的字符串异常

这不起作用,因为Console的方法ReadLine没有像您预期的那样抛出异常。

ReadLine方法可以引发此异常IOException、OutOfMemoryException、ArgumentOutOfRangeException。

您可以在MSDN中查看:https://msdn.microsoft.com/pt-br/library/system.console.readline(v=vs.110).aspx

我想你对异常是如何工作的感到困惑,所以我建议你阅读这篇文章:异常和异常处理(C#编程指南)


要执行您想要的操作,您必须在属性中设置ReadLine的返回,然后运行一些代码来检查这个字符串值是否只包含字母,一种方法是使用Regex,请参阅下面的代码

Console.WriteLine("Please Enter the Item Name");
item1.itemname = Console.ReadLine();
var containOnlyLetters = Regex.IsMatch(item1.itemname.Trim(), @"^[A-Za-z]+$");

您必须使用添加此

using System.Text.RegularExpressions; 

正如我在你的代码中所看到的,你想再次询问它是否没有输入你允许的字符串,所以让我们使用do-for循环来完成这一点,见下面的

for (int tries = 0; tries == 0 || !Regex.IsMatch(item1.itemname, @"^[A-Za-z]+$"); tries++)
{
    if(tries > 0)
        Console.WriteLine("Please enter Name in the Correct Format");
    else
        Console.WriteLine("Please enter the Item Name");
    item1.itemname = Console.ReadLine().Trim();
}

如果你不熟悉Regex,你可以创建一个方法来检查字符串是否只包含在所有字符中循环的字母,并逐个检查,比如:

private static bool ContainsOnlyLetters(string str)
{
    foreach (char c in str)
    {
        if (!char.IsLetter(c))
            return false;
    }
    return true;
}

使用LINQ 可以简化此方法

private static bool ContainsOnlyLetters(string str)
{
    return str.All(c => char.IsLetter(c));
}

如果你使用C#,你可以使用表达式体方法

private static bool ContainsOnlyLetters(string str)
    => str.All(c => char.IsLetter(c));

然后您可以使用ContainsOnlyLetters方法,请参阅以下内容:

for (int tries = 0; tries == 0 || !ContainsOnlyLetters(item1.itemname.Trim()); tries++)
{
    if(tries > 0)
        Console.Write("Please enter Name in the Correct Format");
    else
        Console.WriteLine("Please Enter the Item Name");
    item1.itemname = Console.ReadLine();
}

您可以使用三元表达式来稍微改进以前的代码

for (int tries = 0; tries == 0 || !ContainsOnlyLetters(item1.itemname.Trim()); tries++)
{
    var displayMessage = tries > 0
                         ? "Please enter Name in the Correct Format"
                         : "Please Enter the Item Name"
    Console.WriteLine(displayMessage);
    item1.itemname = Console.ReadLine();
}

这是一个反模式:通过异常控制流。

我怀疑你的意图是这样的(在伪代码中):

try
{
    Console.WriteLine("Please Enter the Item Name");
    item1.itemname = Console.ReadLine();
    if([Put here a condition to validate item1.itemname format]) 
         throw new SomeException();
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
    Console.Write("Please enter Name in the Correct Format");
    if (e.Message != null)
        z = 1;
}

您不应该使用异常,而应该使用正则表达式、条件语句和循环来实现用户输入的试错方法

例如,您可以使用do-while循环来执行迭代,直到用户提供具有有效格式的itemName

string itemName = null;
do
{
    // If it's not the first try you assume that itemName won't be empty
    // so it will show the message to prompt the user for a valid item name
    if (string.IsNullOrEmpty(itemName))
        Console.WriteLine("Please enter the item name");
    else
        Console.WriteLine("Please enter an item name with valid format!");
    itemName = Console.ReadLine();
}
while (!Regex.IsMatch(itemName, "^[a-z]+$", RegexOptions.IgnoreCase));
// Now that you know the itemName is valid, you can set the whole property:
item1.itemname = itemName;

如果您需要对许多属性使用这种输入方法

你可以将这种方法推广为一种方法。我还添加了一个参数来指定在Prompt方法失败之前的有限尝试次数:

// This class will hold data input results
public sealed class DataInputResult 
{
    public DataInputResult(string data, bool isSuccessful = true, string failReason = null)
    {
        Data = data;
        IsSuccessful = isSuccessful;
        FailReason = failReason;
    }
    public string Data { get; private set; }
    public bool IsSuccessful { get; private set; }
    public bool FailReason { get; private set; }
}
public class DataInput
{
    public static Task<DataInputResult> Prompt(string initialMessage, string retryMessage, string regex, int maxTries = 3)
    {
        TaskCompletionSource<DataInputResult> resultCompletionSource = new TaskCompletionSource<DataInputResult>();
        int currentTries = 0;
        string itemName = null;
        bool matches = false;
        while(currentTries < maxTries && !matches)
        {
            // If it's not the first try you assume that itemName won't be empty
            // so it will show the message to prompt the user for a valid item name
            if (string.IsNullOrEmpty(itemName))
                Console.WriteLine(initialMessage);
            else
                Console.WriteLine(retryMessage, currentTries + 1);
            itemName = Console.ReadLine();
            matches = Regex.IsMatch(itemName, regex, RegexOptions.IgnoreCase);
            if(!matches) currentTries++;
        }
        if(matches)
            resultCompletionSource.SetResult(new DataInputResult(itemName));
        else
            resultCompletionSource.SetResult(new DataInputResult(null, false, "Maximum number of tries reached"));

        return resultCompletionSource.Task;
    }
}

您的代码将过于简化为:

DataInputResult itemNameResult = await DataInput.Prompt
(
    "Please enter the item name", 
    "Please enter an item name with valid format! You can still try to give one {0} time(s) more...",
    "^[a-z]+$" // alphabet characters only
);      
DataInputResult itemIdResult = await DataInput.Prompt
(
    "Please enter the item identifier", 
    "Please enter an item identifier with valid format! You can still try to give one {0} time(s) more...",
    "^[0-9]+$" // digits only
);
// Set item object properties if the prompt result was successful:
if(itemNameResult.IsSuccessful)
    item.itemname = itemNameResult.Data;
if(itemIdResult.IsSuccessful)
    item.itemid = itemIdResult.Data;