Why wouldn't `new int[x]{}` be valid? - c#

In MonoDevelop I have the following code which compiles:
int[] row = new int[indices.Count]{};
However, at run-time, I get:
Matrix.cs(53,53): Error CS0150: A
constant value is expected (CS0150)
(testMatrix)
I know what this error means and forces me to then resize the array:
int[] row = new int[indices.Count]{};
Array.Resize(ref row, rowWidth);
Is this something I just have to deal with because I am using MonoDevelop on Linux? I was certain that under .Net 3.5 I was able to initialize an array with a variable containing the width of the array. Can anyone confirm that this is isolated? If so, I can report the bug to bugzilla.

You can't mix array creation syntax with object initialization syntax. Remove the { }.
When you write:
int[] row = new int[indices.Count];
You are creating a new array of size indices.Count initialized to default values.
When you write:
int[] row = new int[] { 1, 2, 3, 4 };
You are creating an array and then initializing it's content to the values [1,2,3,4]. The size of the array is inferred from the number of elements. It's shorthand for:
int[] row = new int[4];
row[0] = 1;
row[1] = 2;
row[2] = 3;
row[3] = 4;
The array is still first initialized to defaults, this syntax just provides a shorthand to avoid havind to write those extra assignments yourself.

The following code fails to compile for the same reason on Windows/.NET/LINQPad:
void Main()
{
int[] row = new int[indices.Count]{};
row[2] = 10;
row.Dump();
}
// Define other methods and classes here
public class indices {
public static int Count = 5;
}
However, removing the object initialisation from the declaration ({}) makes it work.

In C#, if you want to declare an empty array the syntax should be:
int[] row = new int[indices.Count];

Because when you to use use array initialization syntax AND specify the size of the array
int[] arr = new int[5]{1,2,3,4,5};
The size of the array is superfluous information. The compiler can infer the size from the initialization list. As others have said, you either create empty array:
int[] arr = new int[5];
or use the initialization list:
int[] arr = {1,2,3,4,5};

Related

What is the structure of an Array ?

Well I know that Array in C# is an object
but a bit of code has confused me actually
int[] numbers = {4, 5, 6, 1, 2, 3, -2, -1, 0};
foreach (int i in numbers)
Console.WriteLine(i);
to access an arbitrary property of an arbitrary object int value= object.property;
in this loop it's kind of accessing the properties, but how ?
and what is the property itself here ? how they are being organized?
How data is stored
Basically an array is a blob of data. Integers are value types of 32-bit signed integers.
Identifiers in C# are either pointers to objects, or the actual values. In the case of reference types, they are real pointers, in the case of values types (e.g. int, float, etc) they are the actual data. int is a value type, int[] (array to integers) is a reference type.
The reason it works like this is basically "efficiency": the overhead of copying 4 bytes or 8 bytes for a value type is very small, while the overhead of copying an entire array can be quite extensive.
If you have an array containing a N integers, it's nothing more than a blob of N*4 bytes, with the variable pointing to the first element. There is no name for each element in the blob.
E.g.:
int[] foo = new int[10]; // allocates 40 bytes, naming the whole thing 'foo'
int f = foo[2]; // allocates variable 'f', copies the value of 'foo[2]' into 'f'.
Access the data
As for foreach... In C#, all collections implement an interface named IEnumerable<T>. If you use it, the compiler will in this case notice that it's an integer array and it will loop through all elements. In other words:
foreach (int f in foo) // copy value foo[0] into f, then foo[1] into f, etc
{
// code
}
is (in the case of arrays!) the exact same thing as:
for (int i=0; i<foo.Length; ++i)
{
int f = foo[i];
// code
}
Note that I explicitly put "in the case of arrays" here. Arrays are an exceptional case for the C# compiler. If you're not working with arrays (but f.ex. with a List, a Dictionary or something more complex), it works a bit differently, namely by using the Enumerator and IDisposable. Note that this is just a compiler optimization, arrays are perfectly capable of handling IEnumerable.
For those interested, basically it'll generate this for non-arrays and non-strings:
var e = myEnumerable.GetEnumerator();
try
{
while (e.MoveNext())
{
var f = e.Current;
// code
}
}
finally
{
IDisposable d = e as IDisposable;
if (d != null)
{
d.Dispose();
}
}
If you want a name
You probably need a Dictionary.
An array is just a collection, or IEnumerable<T> where T represents a particular type; in your case int (System.Int32)
Memory allocation...
An int is 32 bits long, and you want an array of 10 items
int[] numbers = new int[10];
32 x 10 = 320 bits of memory allocated
Memory access...
Say your array starts at 0000:0000 and you want to access index n [0-9] of the array...
Pseudo code...
index = n
addressof(n) = 0000:0000 + (sizeof(int) * index)
or
index = 2
addressof(n) = 0000:0000 + (32 * 2)
This is a simplified example of what happens when you access each indexed item within the array (your foreach loop sort of does this)
A foreach loop works by referencing each element in the array (in your case, the reference is called i).
Why you are NOT accessing by property...
In an array, items are stored by index, not by name...
... so you can't...
numbers.1
numbers.2
...but you can...
numbers[1]
numbers[2]
Since every object derives from object, you can access arbitrary members of the particular type...
numbers[1].GetHashCode();
Example:
//Define an array if integers, shorthand (see, memory allocation)...
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//For each element in the array (under the hood, get the element's address in memory and hold this in a reference called i)...
foreach(int i in numbers)
{
// Call GetHashCode() on the instance pointed to by i and pass the reference (by value) to the Console.WriteLine method.
Console.WriteLine(i.GetHashCode());
}

How can I dynamically generate and populate a multi-dimensional array

I'm working on a serializer and have run into a real wall with multi-dimensional arrays. If I use Activator.CreateInstance() it creates a one dimensional array just fine, but it fails to work when used as follows:
var indices = new[] { 2, 2 };
Type type = typeof(int[,]);
var result = Activator.CreateInstance(type, indices) as Array;
If I instead use Array.CreateInstance() to generate my array, it works for single and multi-dimensional arrays alike. However, all my calls to the SetValue() method on the array, which I use to dynamically set values, generates an exception, whereas it works fine on the single dimensional arrays I created using Activator.CreateInstance(). I'm really struggling to find a viable solution that allows me to dynamically create an array of any dimension/size and then populate the array with values. I'm hoping someone with more reflection experience can shed some light on this.
When trying to create a multi-dimensional array with Activator I get the exception:
Constructor on type 'System.Int32[,]' not found.
When I instead use Array.CreateInstance() and then call SetValue() I get the following exception from the SetValue() call:
Object cannot be stored in an array of this type.
Which frankly makes no sense to me since the value is an int and the array is an int[,].
I am using the 4.5 framework for my project though I recreated the problem with 4.6 as well.
You can call Array.CreateInstance with the actual ElementType which is int in this case.
var indices = new[] { 2, 3 };
var arr = Array.CreateInstance(typeof(int), indices);
Then you can populate the array with SetValue without any exception. For example
var value = 1;
for (int i = 0; i < indices[0]; i++)
{
for (int j = 0; j < indices[1]; j++)
{
arr.SetValue(value++, new[] { i, j });
}
}
//arr = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]

Index out bounds of array when adding data into an array

So I have some code which stores some data in an array. When new data comes in it is put in a new array item (The totalnumber of array items) then the total number of array items is added too ready for the next bit of data. But when I try to add data into the array, be it array[0] or whatever it throws array index out of bounds?
Declaration:
string[] TabMessages = { };
int TotalTabs = 0;
Using it:
DevComponents.DotNetBar.TabItem Tab = TabStrip.CreateTab(TabName);
Tab.Tooltip = id + "|" + TabIndex;
TabMessages[TotalTabs] = "";//index out of bounds of array
TabStrip.SelectedTab = Tab;
TotalTabs++;
Any help, this is really annoying me because it's throwing the error about the index being out of bounds of the array when I'm trying to create a new entry to the array...
Arrays are a static length. You have defined an array of 0 length, then tried to access an element in the array that does not exist. Either you have to create a large enough array to hold all of the values you intend to use, or use a non-static collection like List<string> instead of a static-sized one like string[].
List<string> TabMessages = new List<string>();
TabMessages.Add("");
If you want something you can access by index, but don't want to supply all possible values, use a dictionary:
Dictionary<int, string> TabMessages = new Dictionary<int, string>();
TabMessages[TotalTabs] = "";
Arrays in C# are not dynamic - they are fixed size. Try using something list a List<string> and using the Add method to insert a new entry into it.
TabMessages is an array of 0 elements (that's how you declared it). As such, you won't be able to add (or set) any element on it - you'll get an index out of bounds exception every time.
This code:
string[] TabMessages = { };
is equivalent to:
string[] TabMessages = new string[0];
it means you created array which size 0. That is why you got this kind of exception. So you can use List<string> instead with dynamic size:
var TabMessages = new List<string>();
Then you can add the first item:
TabMessages.Add(string.Empty);
Or, create string array with fixed size depending on your business rule:
string[] TabMessages = new string[5]; // create string array with 5 elements
Array's are defined as having a fixed size. Declaring string[] TabMessages = {} is the same as string[0] Tabmessages;
You can resize an array (but I think it is a moderately expensive process) - see http://www.dotnetperls.com/array-resize
Alternatively (and preferably), try using some type of List construct

Cannot implicitly convert type 'int' to 'int[]'

I have declared my int[] as follows
int[] iroleID = new int[] { };
My code for getting the values from database and assigning to iroleid is as follows
if (oAuthenticate.getTaskID(out m_oDataSet1, "uspgetTaskID"))
{
for (int iTaskid = 0; iTaskid < m_oDataSet1.Tables[0].Rows.Count; iTaskid++)
{
iroleID = Convert.ToInt32(m_oDataSet1.Tables[0].Rows[iTaskid]["RoleID"].ToString());
strTaskID = m_oDataSet1.Tables[0].Rows[iTaskid]["TaskID"].ToString();
arrTaskID.Add(strTaskID);
}
}
But i am getting an error as mentioned Cannot implicitly convert type 'int' to 'int[]' can any one help me
And no surprise here. Look at
iroleID = Convert.ToInt32(...);
Convert.ToIn32 results in an int just like the compiler claims.
Either do something like:
if (oAuthenticate.getTaskID(out m_oDataSet1, "uspgetTaskID"))
{
var iroleID = new int[m_oDataSet1.Tables[0].Rows.Count];
for (int iTaskid = 0; iTaskid < m_oDataSet1.Tables[0].Rows.Count; iTaskid++)
{
iroleID[iTaskid] = Convert.ToInt32(m_oDataSet1.Tables[0].Rows[iTaskid]["RoleID"].ToString());
/* ... */
}
}
or rethink your algorithm.
PS: I can hardly tell you what exactly to do as you don't show what the purpose of iRoleID is.
off course!
iroleID = Convert.ToInt32(m_oDataSet1.Tables[0].Rows[iTaskid]["RoleID"].ToString());
iroleID is an int array; Convert.ToInt32() returns an int .
so:
-you must declare an int variable tu store Convert.ToInt32() value
or
-just add Convert.ToInt32() result to iroleID ( iroleID.Add(Convert.ToInt32(...)) )
Sure, you can't just assign the int value to the int[] variable. Probably you need to add items to the collection. Change your int[] iroleID = new int[] { }; to List<int> iroleID = new List<int>(); and then change code to:
if (oAuthenticate.getTaskID(out m_oDataSet1, "uspgetTaskID"))
{
for (int iTaskid = 0; iTaskid < m_oDataSet1.Tables[0].Rows.Count; iTaskid++)
{
iroleID.Add(Convert.ToInt32(m_oDataSet1.Tables[0].Rows[iTaskid]["RoleID"].ToString()));
strTaskID = m_oDataSet1.Tables[0].Rows[iTaskid]["TaskID"].ToString();
arrTaskID.Add(strTaskID);
}
}
iroleID = Convert.ToInt32(m_oDataSet1.Tables[0].Rows[iTaskid]["RoleID"].ToString());
This would convert the RoleID columns value to an integer. You are taking this integer and trying to assign it to an integer array which of course is not possible. What exactly is your idea? If it is to populate a single array with all the IDs you can do the same as you did but assign it to a normal integer and then add that integer to a list or something.
You can also just use plain ADO.NET to retrieve all the values from that column and cast it to an List. That would be better.
One problem has already been answered, you must add it to an array giving the position you want
iroleID[iTaskid] = Convert.ToInt32(m_oDataSet1.Tables[0].Rows[iTaskid]["RoleID"].ToString());
the other problem is, that you create an array. You must give the length of the array.
int[] iroleID = new int[m_oDataSet1.Tables[0].Rows.Count];
Use indexing for the int array to assign a value, you can't assign an integer directly to an integer array.
iroleID[0] = Convert.ToInt32(m_oDataSet1.Tables[0].Rows[iTaskid]["RoleID"].ToString());

Adding to an Array

I have an array:
String[] ay = {
"blah",
"blah number 2"
"etc" };
... But now I want to add to this array at a later time, but I see no option to do so. How can this be done? I keep getting a message saying that the String cannot be converted to String[].
Thank you
Use a List rather than an array:
List<string> list = new List<string>();
list.Add( "blah" ) ;
Then, later, if you really do need it as an array:
string[] ay = list.ToArray();
Arrays are of fixed size, so after it has been created, you can't change the size of it (without creating a new array object)
Use the List<string> instead of the array.
Arrays can't change their size after they are declared. Use collections instead. For example: List.
As everyone's already said, use List in the System.Collections.Generic namespace.
You could also use a Hashtable which will allow you to give each string a meaning, or "key" which gives you an easy way to pull out a certain string with a keyword. (as for keeping messages stored in memory space for whatever purpose.)
You could also Create a new array each time you add a value, make the new array 1 bigger than the old one, copy all the data from the first array into the 2nd array, and then add your new value in the last slot (Length - 1)
Then replace the old array with your new one.
It's the most manual way of doing it.
But List and Hashtable work perfectly well too.
If you don't need indexing a specific array element (usage of brackets), but you want to be able to efficiently add or remove elements, you could use LinkedList.
If you do need indexing
have a look at Dictionary data type also in the System.Collection
http://msdn.microsoft.com/en-us/library/xfhwa508.aspx
so you could do something like
Dictionary<int, string> dictionary = new Dictionary<int, string>();
dictionary.Add(1, "afljsd");
You can do this but I don't recommend it:
// Reallocates an array with a new size, and copies the contents
// of the old array to the new array.
// Arguments:
// oldArray the old array, to be reallocated.
// newSize the new array size.
// Returns A new array with the same contents.
public static System.Array ResizeArray (System.Array oldArray, int newSize) {
int oldSize = oldArray.Length;
System.Type elementType = oldArray.GetType().GetElementType();
System.Array newArray = System.Array.CreateInstance(elementType,newSize);
int preserveLength = System.Math.Min(oldSize,newSize);
if (preserveLength > 0)
System.Array.Copy (oldArray,newArray,preserveLength);
return newArray;
}
Here's an extension method to add the to arrays together and create a new string array
public static class StringArrayExtension
{
public static string[] GetStringArray (this string[] currentArray, string[] arrayToAdd)
{
List<String> list = new List<String>(currentArray);
list.AddRange(arrayToAdd);
return list.ToArray();
}
}

Categories