首页 > 解决方案 > 我得到一个 System.IndexOutOfRangeException

问题描述

我当前的代码有问题。我和很多人一样在做一个项目,著名的 SodaCrate 项目。我不想要代码的任何解决方案,但我想知道为什么我不能用“System.IndexOutOfRangeException”解决问题。当我尝试在我的板条箱中添加超过 24 个瓶子时,我收到了这个错误(我为瑞典的评论道歉)。

这是我的代码:

public void add_soda()
{

    Console.WriteLine("\"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\"");
    Console.WriteLine("|     Choose your beverage!        |");
    Console.WriteLine("|                                  |"); // Välkomnar användaren
    Console.WriteLine("|[1] Pepsi , Soda, 11kr            |");
    Console.WriteLine("|[2] Coca-Cola , Soda, 12kr        |");
    Console.WriteLine("|[3] Coors Light , Beer, 18kr      |");
    Console.WriteLine("|[4] Fiji, Water , 13kr            |");
    Console.WriteLine("|[5] Nocco , Energy drink , 22kr   |");
    Console.WriteLine("|[6] Redbull , Energy drink , 25kr |");
    Console.WriteLine("|                                  |");
    Console.WriteLine("\"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\"");

    //Console.WriteLine("[7] Randomize");                       <---------- Fixa

    int temp = 0;

    while (!int.TryParse(Console.ReadLine(), out temp) || !(temp < 7 && temp > 0)) // Detta är en failsafe, ifall väljaren väljer något som är över 7 eller under 1 kommer följande kod att skrivas ut.
    {
        // Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine("Invalid input, please try again.");
        // Console.ResetColor();
    }   

    switch (temp) // Denna switch statementen kommer låta oss lägga till flaskor i vår crate
    {
        case 1: //Om anändaren skriver in ett tal mellan 1 och 6, kommer följade cases att skriva ut deras WriteLines.
            Console.WriteLine(">>> You choose Pepsi <<<");
            myCrate[numberOfBottles] = new Bottle("Pepsi", "Soda", 11); // Här skapas en läsk med namnet Pepsi som kostar 11kr.
            numberOfBottles++; // Denna funktion gör så att en läsk läggs in i craten varje gång den skapas.
            break;
        case 2:
            Console.WriteLine(">>> You choose Coca-Cola <<<");
            myCrate[numberOfBottles] = new Bottle("Coca-Cola", "Soda", 12);
            numberOfBottles++;
            break;
        case 3:
            Console.WriteLine(">>> You choose Coors Light <<<");
            myCrate[numberOfBottles] = new Bottle("Coors Light", "Beer", 18);
            numberOfBottles++;
            break;
        case 4:
            Console.WriteLine(">>> You choose Fiji <<<");
            myCrate[numberOfBottles] = new Bottle("Fiji", "Water", 13);
            numberOfBottles++;
            break;
        case 5:
            Console.WriteLine(">>> You choose Nocco <<<");
            myCrate[numberOfBottles] = new Bottle("Nocco", "Energydrink", 22);
            numberOfBottles++;
            break;
        case 6:
            Console.WriteLine(">>> You choose Redbull <<<");
            myCrate[numberOfBottles] = new Bottle("Redbull", "Energydrink", 25);
            numberOfBottles++;
            break;
        default:
            //Console.ForegroundColor = ConsoleColor.Red;         // <<<<<-----------------   FIXA
            Console.WriteLine("Invalid choice!");
           // Console.ResetColor;
            break;
    }
    try
    {
        if(numberOfBottles >= 25)
        {   
            Console.WriteLine("The crate is currently full!");
        }
    }
    catch (IndexOutOfRangeException e)
    {
        Console.WriteLine(e.Message);
        throw new ArgumentOutOfRangeException("index paramater is out of range", e);
    }
}

谁能给我一个想法或提示为什么抛出异常?我也尝试过 if-else 语句,我目前很困惑。

标签: c#switch-statementtry-catch

解决方案


您发生的问题是由于您尝试访问Bottle[]不存在的一部分。由于您已经实例化了具有特定长度的数组,因此您不能超过该长度。Length最初(并且总是)您应该在尝试访问它之前检查您希望使用的索引与您的数组的属性。假设我们int[]对整个示例都有一个,我们最初给它一个Length3

int[] someNumbers = new int[3];

在上面的例子中,我们创建了一个分配了内存槽的新int数组。3如果我们尝试使用硬编码的数字来访问它,问题就会变得非常明显:

someNumbers[0] = 1;
someNumbers[1] = 2;
someNumbers[2] = 3;
someNumbers[3] = 4; // Blows up here.

的第四个索引3不起作用的原因是因为 inC#集合是使用从零开始的索引访问的;这意味着访问从零开始并从那里爬升。因此,从技术上讲,元素比您认为的要落后一个空间(如果您习惯于从 1 开始的传统数字系统)。

如果您使用相同的主体并使用变量访问数组,则会发生相同的事情,但不太明显;我假设您知道++运营商为此做了什么。

int index = 0;
int[] someNumbers = new int[3];
someNumbers[index++] = 1; // index = 0
someNumbers[index++] = 2; // index = 1
someNumbers[index++] = 3; // index = 2
someNumbers[index++] = 4; // index = 3 :: Blows up here.

3出于完全相同的原因,这在第四个指数上爆炸了。解决这个问题的方法是在访问之前检查索引:

if (index < someNumbers.Length)
    someNumbers[index++] = 1;

此代码有效,因为仅当索引在数组范围内时才会执行分配。


调整阵列大小

现在在其他语言中,有一些方法可以很容易地调整数组的大小;但C#不允许我们这样做。对我们来说是个好东西,有一个解决方法。我将再次int[]用于演示。

假设我们创建了长度为 3 的初始数组:

int[] someNumbers = new int[3];

在路上的某个地方,出于某种原因,我们决定需要 3 个以上的数字;好吧,我们现在需要一个更大的数组。为此(非常低效),您可以创建一个更大的新数组,然后添加所有旧值:

int[] newNumberArray = new int[someNumbers.Length + 10];
for (int i = 0; i < someNumbers.Length; i++)
    newNumberArray[i] = someNumbers[i];

上面的代码创建了一个更大的数组,并将所有旧值放入其中。请记住,这是一种非常低效的方法,我强烈建议使用List<T>或一些类似的对象。


推荐阅读