Question

I have a class with a List and I am accessing it in another classes method. That works fine but when I attempt to use the List in a do-loop I always get a "ArgumentOutOfRangeExcetpion". I'm really confused why using the List inside a do-loop caused it to be empty or at least that's what I think is happening. If some one could explain to me why this is happening it would be very enlightening and maybe I could figure out how I'm gonna get this to work.

Here is my Method:

private void ListToAttributes()
    {
        int count = -1;

        //Finds Attribute starting Line.
        do
        {
            count = count + 1;

        } while (Player.PlayerList[count] != "Attributes;");

        //Adds all Attributes to a list
        List<string> TypeAndAmount = new List<string>();

        do
        {
            TypeAndAmount.Add(Player.PlayerList[count]);
            count = count + 1;
        } while (Player.PlayerList[count] != ".");

        //Sorts by type and adds amount to Player Class


        foreach (string Line in TypeAndAmount)
        {
            string[] Type = Line.Split(' ');

            if (Type[0] == "Mind") { Player.Mind = int.Parse(Type[1]); }
            if (Type[0] == "Body") { Player.Body = int.Parse(Type[1]); }
            if (Type[0] == "Soul") { Player.Soul = int.Parse(Type[1]); }
        }
    }
Was it helpful?

Solution

You first loop will cause an ArgumentOutOfRangeException if no item in the list matches the string. In this case you will happily walk past the end of the list. Your second loop has the same issue.

Further I think you have to increment count one more time between the two loops - currently you are adding the item "Attributes;" to the list TypeAndAmount. This will also cause an ArgumentOutOfRangeException because splitting the string "Attributes;" at spaces yields only one string and you are accessing Type[1] in your last loop.

I suggest rewriting your code using some LINQ (including the step to skip the item "Attributes;").

// Skip everything until we find 'Attributes;'.
var stepOne = Player.PlayerList.SkipWhile(entry => entry != "Attributes;");

// Skip over 'Attributes;'.
var stepTwo = stepOne.Skip(1);

// Take everything until we find '.'.
var stepThree = stepTwo.TakeWhile(entry => entry != ".");

// Stuff everything we selected into a new list.
var typeAndAmount = stepThree.ToList();

You can also put everything into one statement - less verbose but harder to debug.

var typeAndAmount = Player.PlayerList
                          .SkipWhile(entry => entry != "Attributes;")
                          .Skip(1)
                          .TakeWhile(entry => entry != ".")
                          .ToList();

OTHER TIPS

I see a few things wrong that could be causing the exception. In your first loop, you need to check and make sure the array isn't empty, and you need to have a condition to check against the array size, in case "Attributes" isn't there. Maybe try:

if (Player.PlayerList.Length > 0){
  do
  {
    count = count + 1;
  }while (count < Player.PlayerList.Length && Player.PlayerList[count] != "Attributes;");

Note that if Attributes isn't found, you should probably throw your own exception. For the second loop, you need to add similar conditions:

if (count < Player.PlayerList.Length){
  do
  {
      TypeAndAmount.Add(Player.PlayerList[count]);
      count = count + 1;
  } while (count < Player.PlayerList.Length && Player.PlayerList[count] != ".");
}

Note these will just prevent the exceptions. If your list isn't laid out the way this method expects, you'll still end up with problems.

I'm revising my answer based on a best guess. When you hit your 2nd do loop, Player.PlayerList[count] will still be equal to "Attributes". You then enter the 2nd loop and add "Attributes" to TypeAndAmount. When you try and Line.Split(' ') on that line, it will only return an array with one item in it. Type[1] will throw ArgumentOutOfRangeException.

I think if you add count = count +1 before the 2nd do loop, that will fix your problem.

Another clever (I think) way to find your first "Attribute" section, would be to wrap it all in one line:

int count = -1;
while (Player.PlayerList[count++] != "Attributes;");

The ++ notation is just a quicker way of writing count = count + 1. Hopefully you'll find that useful. :)

The problem is in your Do loop, you're raising count by 1 and then it gets evaluated. This leads your count to be bigger than the number of elements.

This would work:

 while (count < Player.PlayerList.Count && Player.PlayerList[count] != "Attributes;");
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top