ArgumentOutOfRange In List - c#

I have a Unity3D Project. In this project I'm supposed to add some data to a list in a specific index number but it throws me the following error:
ArgumentOutOfRangeException: Argument is out of range. Parameter name:
index
This is my code:
foreach (var Player in PhotonNetwork.PlayerList)
{
NameList.Clear();
if ((int)Player.CustomProperties["GameCount"] == First)
{
NameList.Insert(0 ,(string)PhotonNetwork.LocalPlayer.CustomProperties["Name"]);
}
else if ((int)PhotonNetwork.LocalPlayer.CustomProperties["GameCount"] == Second)
{
NameList.Insert(1 ,(string)Player.CustomProperties["Name"]);
}
else if ((int)Player.CustomProperties["GameCount"] == Third)
{
NameList.Insert(2,(string)PhotonNetwork.LocalPlayer.CustomProperties["Name"]);
}
else if ((int)Player.CustomProperties["GameCount"] == Fourth)
{
NameList.Insert(3, (string)PhotonNetwork.LocalPlayer.CustomProperties["Name"]);
}
}

The Insert method looks as this: public void Insert (int index, T item);.
And exception is thrown in two scenarios, as MSDN states in the part about ArgumentOutOfRangeException:
Parameter index is less than 0.
Parameter index is greater than Count.
The first option is not true about your case as you have all your indexes higher than zero. Then it means that in one of your else if's you try to insert a value in position far above the number of existing elements, this causes the exception.
What I can advice you is to make some debugging and look when you have less elements. Or to use Add instead of Insert, more info you can find here.
UPDATE
As an example, when you are trying to perform
NameList.Insert(3, (string)PhotonNetwork.LocalPlayer.CustomProperties["Name"]);
you are trying to insert an element to position 3, but if you have only 1 element in List then your insert throws an error.

If you First element(0) no Insert but Insert second element(1) that argument is out of range. Example: If the program executes first:
NameList.Insert(2,(string)PhotonNetwork.LocalPlayer.CustomProperties["Name"]);
But no executes:
NameList.Insert(0 ,(string)PhotonNetwork.LocalPlayer.CustomProperties["Name"]);

Related

How to compare a data value against values in an list

I'm trying to search through a list of values, which could be any type (int, string, bool, and so-on), and I can't find a way to compare a given value against values in the list.
My code so far:
public void Countin(T data)
{
int numbersOf = 0;
Node pTmp = first;
while (pTmp != null)
{
if (pTmp.Equals(data))
{
numbersOf++
pTmp = pTmp.Next;
}
else
{
pTmp = pTmp.Next;
}
}
Console.WriteLine($"There are {numbersOf} {data} in the list.");
}
With a list of
"I" "am" "getting" "really" "really" "tired" "of" "this",
I keep getting the output of "There are 0 really in the list". And when I swap the numbersOf++ from to the 'else', I get "There are 8 really in the list."
The rest of the code works fine, it's just that "pTmp.Equals(data)" isn't doing what I think it should be doing, but I can't just use pTmp == data, due to 'data' being an element in a list.
Any help?
Every part of the above code works fine EXCEPT FOR COMPARING pTmp TO data! Nothing else needs help! I just need a way to compare the data variable to the values in the list.
FINAL EDIT:
All I had to do was change the boolean to if (Equals(pTmp.Data),data), and it worked. All I needed as an answer was 'Equals(x,y) will do what you want'. Thanks guys.

Index out of range using lists and for loop

I have this loop here, which for each question it is supposed to create, it generates and then formats a 'worded question' from an array of questions, such as; 'What is the sum of {0} + {1}?'. This loop then formats it, adds the worded question and the answer to an array.
// Use for loop to create the correct amount of questions
for (int i = 0; i < Data.Questions.numQuestions; i++)
{
Random rnd = new Random();
Data.Questions.Sum sum = new Data.Questions.Sum();
// Create part one and part two of the question using random numbers
// ex. 3 + 5
// 3 = partOne, 5 = partTwo
int partOne = rnd.Next(Data.Questions.Sum.min, Data.Questions.Sum.max);
int partTwo = rnd.Next(Data.Questions.Sum.min, Data.Questions.Sum.max);
// Randomly select one of the word questions
string fullQuestion = Data.Questions.Sum.wordedQuestions[rnd.Next(0, Data.Questions.Sum.wordedQuestions.Length)];
// Format the string with the generated numbers
fullQuestion = string.Format(fullQuestion, partOne, partTwo);
// Set out-of-class variables to be displayed to the user
Data.Questions.Sum.questions[i] = fullQuestion;
Data.Questions.Sum.answers[i] = partOne + partTwo;
}
Both Data.Questions.Sum.questions and Data.Questions.Sum.answers are List<string>'s and List<int>'s.
However, when this loop is run, with i = 0, I am thrown;
System.ArgumentOutOfRangeException: 'Index was out of range. Must be
non-negative and less than the size of the collection. Parameter name:
index'
Does anyone know what I'm doing wrong? As far as I know lists are dynamic, and I've defined like this;
// Arrays containing all questions and answers
// used to display questions and check answers
public static List<string> questions = new List<string>();
public static List<int> answers = new List<int>();
Also, to clarify, I do not want to use .Add(), as I have a settings panel which when you hit apply, re-runs this loop so the questions are up to date to the current settings. I need the loop to override the previous values.
Edit:
When using arrays, the better option here, I get;
System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'
On assigning Data.Questions.Sum.answers[i], after assigning the array like so; public static int[] answers {};
If you can't .Add() in this lists - create a copy of this lists and .Add() there. Lists has special for that kind of thing: new List<T>(IEnumerable<T>)
If you need to dynamically scale the collection, but you also need to iterate over it multiple times, then you'll need to check whether it is large enough to either insert, or just update.
You can do this with an extension method such as this...
public static class ListExtentions
{
public static void AddOrUpdate<T>(this List<T> that, int index, T value)
{
if (that.Count > index)
{
that[index] = value;
}
else
{
that.Add(value);
}
}
}
...which can then be called like this...
list.AddOrUpdate(index, value);
...however you can make things easier for yourself if you know how many questions you are going to have to start with.
If the number of questions changes when your UI changes, then you will also have to deal with the issue have scaling down the collection to ensure old elements are removed, which is much simpler if you just re-instantiate the collections every time you need to regenerate the questions / answers.
This is likly to be cause of your problem,(I have asked for clarification in comments where you didn't reply).
Still putting this as an answer, as it is potential error spot and you need to fix this.
As you mentioned you are facing this exception on i=0. there are high chanced that this is every time case not any specific case.
If Data.Questions.Sum.questions is empty then, Data.Questions.Sum.questions[i] = fullQuestion; , will surely throw such exception. Same way for Data.Questions.Sum.answers too.
In such case, you must use .Add() to insert into list.
so your code should be,
if (Data.Questions.Sum.questions.Count > i)
Data.Questions.Sum.questions[i] = fullQuestion;
else
Data.Questions.Sum.questions.Add(fullQuestion);
But if they are not empty, it must not be the cause of this exception.
One more thing i have noticed in your code is Data.Questions.Sum.wordedQuestions.
Even if you have valid list (here Data.Questions.Sum.wordedQuestions) - as you have Length prop, it must be Array not list.
If it is empty, while doing this
string fullQuestion = Data.Questions.Sum.wordedQuestions[rnd.Next(0, Data.Questions.Sum.wordedQuestions.Length)];
this line will surely throw
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
as you are trying to get 0th index's data from it.
So before fetching data from list or array, first you need to check if it does have data init, and also it does have that index which you are asking.
something like
string fullQuestion = string.Empty;
if (Data.Questions.Sum.wordedQuestions != null &&
Data.Questions.Sum.wordedQuestions.Length > 0)
{
//here the way you are creating random number,
// you are assured about index is present in array.
int indexForWordedQuestion = rnd.Next(0, Data.Questions.Sum.wordedQuestions.Length);
fullQuestion = Data.Questions.Sum.wordedQuestions[indexForWordedQuestion];
}

Why am I getting this exception

I have a System.Data.DataSet and 1 single table in it. The table has many columns.
In a certain event handler, I am setting a decimal value for one of the fields, in a data row which is already existing (at the time of setting).
In a very rare case, I am getting a ArgumentOutOfRangeException exception.
Message: System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Call Stack:
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List`1.get_Item(Int32 index)
at System.Data.RecordManager.NewRecordBase()
at System.Data.DataTable.NewRecord(Int32 sourceRecord)
at System.Data.DataRow.BeginEditInternal()
at System.Data.DataRow.set_Item(DataColumn column, Object value)
at CPITS.Data.OrdersRow.set_ExecutionPrice(Decimal value)
Strange thing is, this is happening from the code which the framework has generated (Of course, I didn't write the Setter for the DataColumn).
Can you please help me understand & fix this problem?
EDIT
Below is the code where I am setting value:
void ibclient_OrderStatus(object sender, OrderStatusEventArgs e)
{
Data.OrdersRow drOrders = data.Orders.FindByOrderId(e.OrderId);
if (drOrders != null)
{
drOrders.FilledQuantity = e.Filled;
drOrders.ExecutionPrice = e.AverageFillPrice; //Sporadic Exception when setting a decimal value
}
}
Here is de decompiled code of RecordManager.NewRecordBase
internal int NewRecordBase()
{
int num;
if (this.freeRecordList.Count != 0)
{
num = this.freeRecordList[this.freeRecordList.Count - 1];
this.freeRecordList.RemoveAt(this.freeRecordList.Count - 1);
}
else
{
if (this.lastFreeRecord >= this.recordCapacity)
this.GrowRecordCapacity();
num = this.lastFreeRecord;
++this.lastFreeRecord;
}
return num;
}
as you can see, the only case where you could have a "index out of bounds" exception is here:
num = this.freeRecordList[this.freeRecordList.Count - 1];
since there DataTable is not thread safe, we could easily imagine a scenario where a record is removed by another thread before accessing the freeRecordList[..] but after having accessed to this.freeRecordList.Count.
In this case, freeRecordList.Count would have changed in the meanwhile => index out of bounds exception.
Thus, if I were you, I would try to find a concurrency issue (the fact that it happens in rare cases is another argument !)
Check the number of decimal places you are allowing in your table and check how many decimals the number you are committing has.
This exception can be thrown if the number of decimals is out of range.
DataTable.GetErrors Method
Gets an array of DataRow objects that contain errors.

How to check if key pair in 2D array exists?

I have this 2d array or struct
public struct MapCell
{
public string tile;
}
public MapCell[,] worldMap;
But there's no way to check if key pair is exists in this array or not... No methods for that available.
I tried to do it like this
if (worldMap[tileX, tileY] != null) {
}
it doesnt work:
Error 1 Operator '!=' cannot be applied to operands of type 'Warudo.MapCell' and '<null>'
and for
if (worldMap[tileX, tileY].tile != null) {
it doesn't work either (exception pops up when it hits non existing element).
Index was outside the bounds of the array.
So, how do I check if key pair is exists or not?
You never mentioned which error you are getting -- array out of bounds or a null reference. If you are getting array out of bounds you should precede your null check with something along the lines of...
// make sure we're not referencing cells out of bounds of the array
if (tileX < arr.GetLength(0) && tileY < arr.GetLength(1))
{
// logic
}
Of course, it's best to just store the maximum array bounds instead of getting their lengths each time.
I also second (third?) the recommendation for using a class and not a struct.
Edit: Are you ever actually initializing this field? You haven't included it in your code sample. For example worldMap = new MapCell[100,100];, and then fill up the array...
If you're using an array of struct values, they always exist (once the array is constructed), but have their default value until you set them.
I would recommend using a class here instead of a struct. This will allow you to check for null, as well as act more in an expected fashion if you're going to be changing values (which, given the names, I expect...)
That being said, you could check for whether the string within the struct is null:
if (worldMap[tileX, tileY].tile != null)
{
// You've set the "tile" field inside of this "cell"...
This works because the default value of a struct is initialized with all references, including strings, to null.

C# Determing whether any element in a string array contains a given string anywhere

I have a string array:
string[] Animals = {"Cat", "Dog", "Fish"};
I then want to determine which element contains the sequence "is" and return that entire element; in this case "fish"
If I want to find "gh", it does not exist in the list, so it should return the first element, in this case "Cat"
I've tried this linq code, but i don't think I'm doing the lambda part right.
int index = Animals.Where(x => x.IndexOf("is") >= 0).First().IndexOf("is")
string result = index > 0 ? Animals[index] : Animals[0];
This code throws this error:
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: value
I think I'm close, I just can't seem to get it.
This method obviously isn't fool proof, it should return the first instance of "is" which could be problematic. My potential list is fairly small and the index word is always unique.
Try this:
string result = Animals.FirstOrDefault(x => x.Contains("is")) ?? Animals.First();
(This will fail if the array contains no elements; what do you want to do in this case? You could try FirstOrDefault for the fallback expression as well - this will return null if the sequence is empty.)
Given your requirements, the code you posted has 2 issues:
It uses Enumerable.First, which will throw an exception on an empty sequence i.e. if no item exists that matches the original predicate.
The index you are using in the the second statement is the index of the "is" substring in the result of the first query, not the index of the result in the original array. Consequently, it does not make sense to use that number to index the original array.

Categories