I have this C# code:
data[j].Actual[0] = data[j].Actual.Count != 0 ? (data[j].Actual[0] ?? 0) : 0;
What I want to do is to check if the count is 0, in this case the value of the variable should be set on 0.
In case the count is different of 0, I want to check with null-coalescing operator if that value is there, otherwise return 0.
The problem I have is that I get this error message:
Index was out of range. Must be non-negative and less than the size of
the collection. Parameter name: index
My guess is that even when data[j].Actual.Count is 0 it doesn't the result to 0 but it tries to do something with the null-coalescing operator.
Any suggestions?
I think the problem is the assignment; if data[j].Actual is an empty (list/array/whatever), then you can't just assign data[j].Actual[0] to anything. If this is an array, you can't do anything (except maybe create a new array). If this is a list, you would need to .Add a value.
I would simplify the code:
var actual = data[j].Actual;
if (actual.Count == 0)
{
actual.Add(0);
// or if this is an array: data[j].Actual = new double?[] {0};
}
else if (actual[0] == null)
{
actual[0] = 0;
}
This isn't one line, but it is easy to understand.
look carefully
data[j].Actual[0] = data[j].Actual.Count != 0 ? (data[j].Actual[0] ?? 0) : 0;
You are assigning to Actual[0]. if Actual.Count is 0 you get out of range exception. you cant use ternary. use if statement.
if(data[j].Actual.Count != 0)
{
data[j].Actual[0] = data[j].Actual[0] ?? 0;
}
// else you don't need to set anything because there is nothing to set!
Related
Sometimes the elements that I am checking against do not exist and the application throws an error.
if(responseSerialNumber.ElementAt(1) == 0)
{
//Do the following
}
How can I do deal with this?
There are 2 ways of solving this problem.
First, just check if the array has enough elements before accessing:
if(responseSerialNumber.Length > 2 && responseSerialNumber.ElementAt(1) == 0)
{
//Do the following
}
The second way is to use ElementAtOrDefault() which returns the appropriate default value based on the type of the array.
var item = responseSerialNumber.ElementAtOrDefault(1);
if (item != default(byte)) { // or use "(item != null)" if item is an reference type
//Do the following
}
BEWARE: The second solution would work fine if you have an array of non-value types (in this case they can have null as default value). If you have byte array, stick with the first solution.
If responseSerialNumber is an array byte[] (see comments) you can check the array: first for its Length then for the value
if (responseSerialNumber.Length >= 2 && responseSerialNumber[1] == 0) {
...
}
Or (for arbitrary indexAt and valueToTest):
if (responseSerialNumber.Length >= indexAt + 1 &&
responseSerialNumber[indexAt] == valueToTest) {
...
}
In general case (when responseSerialNumber is IEnumerable<T>) for given
int indexAt = 1;
valueToTest = 0;
we can Skip indexAt items and check the very next one:
if (responseSerialNumber.Skip(indexAt).Take(1).Any(item => item == valueToTest)) {
// responseSerialNumber has at least indexAt items
// indexAt's items is equal to valueToTest
}
Or even
if (responseSerialNumber.Where(index, value) =>
index == indexAt && value == valueToTest)) {
...
}
I have a problem with my code. Compiler stop on this line when I try to pick up the object.
ekwipunek.ListaNaszychPrzedmiotow[i] = BazaDanych_Eq.ListaPrzedmiotow [IdPrzedmiotu];
ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
if ( Input.GetKeyDown (KeyCode.Q))
{
IdPrzedmiotu = DoPodniesienia.GetComponent<PrzedmiotPodniesienie>().id;
for (int i = 0; i < ekwipunek.ListaNaszychPrzedmiotow.Count; i++)
{
if (ekwipunek.ListaNaszychPrzedmiotow[i].id == 0 && DoPodniesienia != null)
{
ekwipunek.ListaNaszychPrzedmiotow[i] = BazaDanych_Eq.ListaPrzedmiotow [IdPrzedmiotu];
Destroy(DoPodniesienia);
DoPodniesienia = null;
}
}
}
Your problem, more than likely, exists because one of your indices on this line references something that would be outside of the range of the collection.
You're setting this variable that is used as an index to an id.
IdPrzedmiotu = DoPodniesienia.GetComponent<PrzedmiotPodniesienie>().id;
Then, you're referencing it further down without verifying that it is available in your collection.
BazaDanych_Eq.ListaPrzedmiotow [IdPrzedmiotu]
You need to validate this value or this collection before accessing it.
Future Debugging Tip: ArgumentOutOfRangeException
Check the count of any collection you are using
Check the value of any index you will use to reference the collection
public class YourClass
{
...
Debug.Log($"The collection \"ListaNaszychPrzedmiotow\" is {ListaNaszychPrzedmiotow.Count()}");
Debug.Log($"The index value of \"i\" is {i}");
...
}
My code was giving me Index out of Range exception for a certain input. Below is the problematic code:
string[] snippetElements = magic_string.Split('^');
string a = snippetElements[10] == null ? "" : "hello";
string b = snippetElements[11] == null ? "" : "world";
For that particular input, array snippetElements had only one element in it, hence while trying to index 10th and 11th element, I got the exception.
For now, I have introduced the following check:
if (snippetElements.Length >= 11)
{
string a = snippetElements[10] == null ? "" : "hello";
string b = snippetElements[11] == null ? "" : "world";
}
Can someone suggest a better way to write this check. Somehow the number 11 is not looking good in the code.
Yes this is an old post, but still helpful. You could use this which I think is cleaner:
string a = snippetElements.ElementAtOrDefault(10) ?? "hello";
string b = snippetElements.ElementAtOrDefault(11) ?? "world";
Can someone suggest a better way to write this check. Somehow the
number 11 is not looking good in the code.
Well you are accessing the element with 11 index, if you have that index in your variable then you can use that in your check, otherwise 11 is fine in your check. Your check should be if(index < snippetElements.Length)
Something like:
int index = 11;
if(index < snippetElements.Length)
{
string b = snippetElements[index] == null ? "" : "world";
}
snippetElements[11] is the 12th element.
if (snippetElements.Length >= 12)
As long your are actually using the [10] and [11] indexes it doesn't look wrong to use the 12 in the if statement.
You can generalize the problem to an extension method like this:
public static class ArrayExtensions
{
public static bool TryIndex<T>(this T[] array, int index, out T result)
{
index = Math.Abs(index);
result = default(T);
bool success = false;
if (array != null && index < array.Length)
{
result = (T)array.GetValue(index);
success = true;
}
return success;
}
}
And convert your code to:
string[] snippetElements = magic_string.Split('^');
string a = null;
string b = null;
if (snippetElements.TryIndex(10, out a) && snippetElements.TryIndex(11, out b))
{
}
Or, more like your source code and using the TryIndex(...) extension method:
string[] snippetElements = magic_string.Split('^');
string a = null;
string b = null;
snippetElements.TryIndex(10, out a);
snippetElements.TryIndex(11, out b);
a = a ?? "hello"; // Null coalesence ?? operator is great!
b = b ?? "world";
It makes the array indexed access safer since your code won't never throw ArgumentOutOfRangeException.
Note that this extension method will work for any kind of array, regardless of its type! Either if its a value type (int, byte...) or a reference type (string, your own classes...).
The logic here is wrong.
If your Split method produces less than 12 elements your indexing on the array snippetElements could go only from zero to (Length - 1) of the array.
In that case there aren't elements at index 10 or 11. And, in any case, if the snippetElement.Lenght is equal or greater than 12, then the elements in the array can't be null. Or they contain a string or they will be empty strings.
You could just write
string a = snippetElements.Length >= 12 ? "hello" : string.Empty;
string b = snippetElements.Length >= 12 ? "world" : string.Empty;
It might be late now, but for any one else who's having the same problem, that's how I solved it. I usually use this logic inside a for loop.
int index = 10;
string a = (index < snippetElements?.Length) ? snippetElements[index] : string.Empty;
snippetElements?.Length checks if snippetElements is not empty then it calls its Length property. Accessing Length property of an empty array results in an exception.
snippetElements[index] (you could replace this with "hello" as in your example) is accessed only if the index is in the bound of an array. Otherwise, it assigns String.Empty to a.
I have some problem with this line of code:
if(String.IsNullOrEmpty(m_nameList[index]))
What have I done wrong?
EDIT: The m_nameList is underlined with red color in VisualStudio, and it says "the name 'm_nameList' does not exist in the current context"??
EDIT 2: I added some more code
class SeatManager
{
// Fields
private readonly int m_totNumOfSeats;
// Constructor
public SeatManager(int maxNumOfSeats)
{
m_totNumOfSeats = maxNumOfSeats;
// Create arrays for name and price
string[] m_nameList = new string[m_totNumOfSeats];
double[] m_priceList = new double[m_totNumOfSeats];
}
public int GetNumReserved()
{
int totalAmountReserved = 0;
for (int index = 0; index <= m_totNumOfSeats; index++)
{
if (String.IsNullOrEmpty(m_nameList[index]))
{
totalAmountReserved++;
}
}
return totalAmountReserved;
}
}
}
If m_nameList is null, that will still blow up, because it will try to find the element to pass to String.IsNullOrEmpty. You'd want:
if (m_nameList == null || String.IsNullOrEmpty(m_nameList[index]))
That's also assuming that index is going to be valid if m_nameList is non-null.
Of course, this is checking if the element of an array is null or empty, or if the array reference itself is null. If you just want to check the array itself (as your title suggests) you want:
if (m_nameList == null || m_nameList.Length == 0)
EDIT: Now we can see your code, there are two problems:
As Henk showed in his answer, you're trying to use a local variable when you need a field
You're also going to get an ArrayIndexOutOfBoundsException (once you've used a field) due to this:
for (int index = 0; index <= m_totNumOfSeats; index++)
That will perform m_totNumOfSeats + 1 iterations because of your bound. You want:
for (int index = 0; index < m_totNumOfSeats; index++)
Note that m_nameList[m_totNumOfSeats] is not valid, because array indexes
start at 0 in C#. So for an array of 5 elements, the valid indexes are 0, 1, 2, 3, 4.
Another option for your GetNumReserved method would be to use:
int count = 0;
foreach (string name in m_nameList)
{
if (string.IsNullOrEmpty(name))
{
count++;
}
}
return count;
Or using LINQ, it's a one-liner:
return m_nameList.Count(string.IsNullOrEmpty);
(Are you sure you haven't got it the wrong way round though? I would have thought reservations would be the ones where the name isn't null or empty, not the ones where it is null or empty.)
If it's the wrong way round, it would be this instead in LINQ:
return m_nameList.Count(name => !string.IsNullOrEmpty(name));
After Edit2:
You are defining m_nameList as a local variable of the constructor.
The rest of your code needs it as a field:
class SeatManager
{
// Fields
private readonly int m_totNumOfSeats;
private string[] m_nameList;
private double[] m_priceList;
// Constructor
public SeatManager(int maxNumOfSeats)
{
m_totNumOfSeats = maxNumOfSeats;
// Create arrays for name and price
m_nameList = new string[m_totNumOfSeats];
m_priceList = new double[m_totNumOfSeats];
}
....
}
To avoid the error you can perform some pre conditions in the if, like these :
if(m_nameList == null || index < 0 || m_nameList.Length < index || String.IsNullOrEmpty(m_nameList[index]))
This should works fine(without causing error) in almost any conditions ...
I stumbled upon this while doing a review and the author is not available:
int n = Convert.ToInt32(text);
if (((n > 0) || (n < 0)) || (n == 0))
{
return 1;
}
The code in general looks solid and it's hard for me to believe that the only purpose of this snippet is to confuse reviewers, but I don't see a way for this condition to fail. Am I missing something?
This may be a remnant of a nullable type. See here at msdn for an explanation, but basically if your code was originally this:
int? n = StringToInt(text); // People roll their own functions to do this, though
// they really shouldn't
if (((n > 0) || (n < 0)) || (n == 0))
{
return 1;
}
Then this could possibly fall through. Each of the statements above would be false, as n could be null from the function, assuming it returned null on a bad input, and the code supported nullable types.
Unlikely, but when looking at "maintained code" anything is possible. But as written, it MUST return 1 (or throw an exception, as mentioned by others in this thread).
It will always return true, assuming it gets there.
Consider:
bool x = (n > 0) || (n < 0);
bool y = (n == 0);
if (x || y)
{
return 1;
}
If n is not zero then either n > 0 or n < 0 is true, so x is true and y is false.
If n is zero, n == 0 is true, so x is false and y is true.
Either way, one side of the OR is true.
That sure looks like a 100% true statement to me. All those parentheses shouldn't matter in the least, since || is associative, i.e.,
(a || b) || c == a || (b || c) == a || b || c
If you overload the relational operators for your class, it might be the case that the condition evaluates to false, but since n is an int, it always evaluates to true
It's possible that int n = Convert.ToInt32(text); could throw an exception, in which case the if statement never even gets evaluated.
See Convert.ToInt32() on MSDN.
As above, it will always be true because, by definition, any real number is either zero, less than zero or greater than zero, and you have covered all cases in your code.
Always will be 1, unless Convert.ToInt32(text) throws an exception.
I don't see how it can evaluate to false.
If, however, n was declared at a different scope where more than a single thread had access to it and one of these threads changes its value, theres quite a high chance the condition would fail.
it will always be true as you write all the states it might be (e.g < > ==)
Yes, it could also throw an exception if the conversion fails :-)