What's wrong with my array declaration? - c#

The following works:
int[] numbers = new int[2];
The following doesn't:
int Size = 2;
int[] numbers = new int[Size];
Error: "A field initializer cannot reference the non-static field, method, or property"
I know this must be me doing something stupid but can't work out what it is at all.

You can give size of array by constant but not variable as the size of array could not be given at class level if you declare the array out side the method at class level. C# does not guarantee the order in which fields within a class are initialized so you cannot use one non-static field to initialize another non-static field outside of a method, reference.
const int Size = 2;
int[] numbers = new int[Size];
void SomeFun()
{
}
If you declare it inside some method then you wont get error.
void SomeFun()
{
int Size = 2;
int[] numbers = new int[Size];
}
You can use list instead of array if your collection size in unknown at runtime.
List<int> lst = new List<int>();

Put these initializations into the constructor:
public class MyClass
{
const int Size;
int[] numbers;
public MyClass()
{
this.Size = 2;
this.numbers = new int[this.Size];
}
}
In this way you are providing a guarantee of order in which initializations should be executed.

You cannot use an instance variable to initialize another instance variable. There is no guarantee that the 'Size' variable will be initialized before the 'number' array. The initial values for fields need to use constants - it's not as restrictive as that; they can also reference static fields, methods or properties.

Related

C# passing int[] (array) with and without ref [duplicate]

This question already has answers here:
Why would ref be used for array parameters in C#?
(2 answers)
What is the use of "ref" for reference-type variables in C#?
(10 answers)
Closed 7 years ago.
I am slightly confused about this, as I have read that an int[] array, although int is a primitive type, since it's an array, it's a reference type variable.
What is the different then between a method such as:
public static void ChangeSomething(ref int[] array)
{
array[0] = 100;
}
and
public static void ChangeSomething(int[] array)
{
array[0] = 100;
}
When the array is modified, I can see the new value of 100 at index 0 for both of these calls.
Is there something different that happens under the covers which makes one better than another? Does the VS IDE allow both simply because perhaps the "ref" keyword clarifies the intention?
The difference is that you can assign the original variable directly in the method. If you change your method to the this:
public static void ChangeSomething(ref int[] array)
{
array = new int[2];
}
And call it like this:
var myArray = new int[10];
ChangeSomething(ref myArray);
Console.WriteLine(array.Length);
You will see that myArray only have a length of 2 after the call. Without the ref keyword you can only change the content of the array, since the array's reference is copied into the method.
If you modify the items of the array, there is no difference.
But if you redefined the array itself with larger array, there is the difference:
public static void ChangeSomething(ref int[] array)
{
array = new int[100]; //you are changing the variable of caller
}
and
public static void ChangeSomething(int[] array)
{
array = new int[100]; //you are changing local copy of array variable, the caller array remains same.
}

C# add variable to the array

I want to use variable from other functions to array something like that:
int arg1 = int.Parse(Textbox1.Text);
int arg2 = int.Parse(Textbox2.Text);
int[] array1 = {arg1, arg2};
But it doesn't work please help
I tried something easier
int arg1 = 0;
int arg2 = 1;
int[] DaneInt = { arg1, arg2};
And still the same error for arg1 and arg2:
a field initializer cannot reference the nonstatic field method or
property
I think you have placed it before the Constructor. Any object initializer used outside a Constructor has to refer to static members. You got this error because the instance has to be initialized before you can access the properties of its class. You should place your code inside the Constructor.
As Jeff pointed out in his comment, the main problem (and the only problem unless you mess up somewhere else) is that you may has passed some non-digit character, which caused the problem. I would recommend that you try it this way using a TryParse(),
int[] array1 = new int[2]; // Array of 2 elements
int arg1 = int.TryParse(Textbox1.Text, array1[0]); // At zero index
int arg2 = int.TryParse(Textbox2.Text, array1[1]); // At 1 index
This would work, and if it doesn't, good thing that you can show an error message in a way
if(int.TryParse(Textbox1.Text, array1[0]) {
// Worked
} else {
// Didn't work
}
Plus: There is a problem with case-sensitivity in your code. The control TextBox has a field Text, not text. That is also a problem in your code, you should consider keeping that in mind also.
Edit
In your comment you have mentioned that the error that you are getting is, a field initializer cannot reference the nonstatic field method or property that means that you are trying to use this variable (IMO; Textbox1) in a separate class or Window. In that case, you cannot use it just the way it is, because it is nonstatic. To reference it, create a class instance,
var text = new MainWindow().TextBox1.Text;
This will create an instance for the Window (remember, WPF has no Form, it has a Window control) and then it will reference the TextBox control to access the property Text.
You are missing the type of the array you want to create using arg1 and arg2.
Add the array type like this:
int[] array1 = new int[] { arg1, arg2};
It should work!

Is there a reason for array declaration syntax in C#?

I was wondering what's the reason behind the syntax? I mean it's like this:
int[ , ] arrayName = new int[10,10];
Wouldn't it be simpler if we had something like:
int[10,10] arrayName ;
What caused the software architect to make such a decision?
It's because you can declare the variable in one scope, and initialize it in another (normally in a constructor).
Something like this:
public class Foo
{
private int[ , ] Bar; // Bar will be null until initialized
public Foo(int a, int b)
{
Bar = new int[a, b];
}
}
With int[10,10] arrayName; you are committing to the array size. What would happen if I did this?
int[10,10] arrayOne;
int[11,11] arrayTwo;
arrayOne = arrayTwo;
An array object is simply a pointer to a block of managed memory. Knowing this, arrayOne = arrayTwo would have to be technically legal.
Therefore, stating that it as an int[10,10] is actually a lie. It may start that way, but it could at any time be reassigned into an array of different dimensions.
This
int[ , ] arrayName = new int[10,10];
already initializes the variable in memory and instantiate it. Also, you could change the size of the array during runtime, for example
arrayName = new int[20,20]
On the other hand
int[10,10] arrayName ;
Will just declare the variable for the array. arrayNamethen is still null.
int[,] arrayName = new int[10,10];
Only the left hand side is declaring the array, the right hand side is initialising it. This is true for most (if not all) of variables in C#. For example
string test; //declaring
test = "test"; //initialising
string test = "test"; //declare and initialise

Structs: field must be fully assigned compiler error

I've declared the following struct:
struct StartPositions
{
public Vector2 pacman;
public Vector2[] ghosts;
// Constructor accepts a Vector2, and an array of Vector2's.
public StartPositions(Vector2 pacmanPosIn, Vector2[] ghostsPosIn)
{
pacman = pacmanPosIn;
for(int a=0;a<ghostsPosIn.Length;a++)
{
ghosts[a] = ghostsPosIn[a];
}
}
}
However I get a compiler error saying the ghosts field must be fully assigned. What I want to do is pass in a Vector2, and a Vector2 array when I create a StartPositions object - making a copy of that array.
How can I do this correctly?
You did not initialize the ghosts array. You need to add a call to new.
public StartPositions(Vector2 pacmanPosIn, Vector2[] ghostsPosIn)
{
pacman = pacmanPosIn;
ghosts = new Vector2[ghostsPosIn.Length];
....
}
And you can simplify the code by replacing the for loop with a call to Array.Copy().
Array.Copy(ghostsPosIn, ghosts, ghosts.Length);
You have to initialize your ghosts array first:
struct StartPositions
{
public Vector2 pacman;
public Vector2[] ghosts;
// Constructor accepts a Vector2, and an array of Vector2's.
public StartPositions(Vector2 pacmanPosIn, Vector2[] ghostsPosIn)
{
pacman = pacmanPosIn;
ghosts = new Vector2[ghostsPosIn.Length];
for(int a=0;a<ghostsPosIn.Length;a++)
{
ghosts[a] = ghostsPosIn[a];
}
}
}
You didn't initialize ghosts array.
public StartPositions(Vector2 pacmanPosIn, Vector2[] ghostsPosIn)
{
...
ghosts = new Vector2[ghostsPosIn.Length];
...
}
From C# Language Specification;
Actual array instances are created dynamically at run-time using the
new operator. The new operation specifies the length of the new array
instance, which is then fixed for the lifetime of the instance.
One annoying quirk in .net is that unless one is using "unsafe" code the concept of a value-type array does not exist. The struct as shown contains a position for the "pacman" and a reference to a mutable array that holds the positions of the ghosts. This is an evil combination, since the struct may appear to encapsulate the positions of the ghosts, but it does not. Thus, if one were to say:
StartPositions p1 = whatever();
... do some stuff
StartPositions p2 = p1;
p2.pacman.X += 3;
p2.ghosts[0].X += 3;
the code would add three to p2.pacman and p2.ghosts[0]; it would not affect p1.pacman.X but would add three to p1.ghosts[0]. Such behavior would likely cause confusion.
If your intention is that StartPositions will be read-only, it should probably never expose the ghosts array directly; instead, ghosts should be a property of type IList<Vector2>, and your constructor should set it to something like a new ReadOnlyList<Vector2> initialized with a copy of the passed-in positions. If it does that, then ghosts can simply be a read-only property that returns such positions.

Passing Arrays by Value and by Reference

These are example from a c# book that I am reading just having a little trouble grasping what this example is actually doing would like an explanation to help me further understand what is happening here.
//creates and initialzes firstArray
int[] firstArray = { 1, 2, 3 };
//Copy the reference in variable firstArray and assign it to firstarraycopy
int[] firstArrayCopy = firstArray;
Console.WriteLine("Test passing firstArray reference by value");
Console.Write("\nContents of firstArray " +
"Before calling FirstDouble:\n\t");
//display contents of firstArray with forloop using counter
for (int i = 0; i < firstArray.Length; i++)
Console.Write("{0} ", firstArray[i]);
//pass variable firstArray by value to FirstDouble
FirstDouble(firstArray);
Console.Write("\n\nContents of firstArray after " +
"calling FirstDouble\n\t");
//display contents of firstArray
for (int i = 0; i < firstArray.Length; i++)
Console.Write("{0} ", firstArray[i]);
// test whether reference was changed by FirstDouble
if (firstArray == firstArrayCopy)
Console.WriteLine(
"\n\nThe references refer to the same array");
else
Console.WriteLine(
"\n\nThe references refer to different arrays");
//method firstdouble with a parameter array
public static void FirstDouble(int[] array)
{
//double each elements value
for (int i = 0; i < array.Length; i++)
array[i] *= 2;
//create new object and assign its reference to array
array = new int[] { 11, 12, 13 };
Basically there is the code what I would like to know is that the book is saying if the array is passed by value than the original caller does not get modified by the method(from what i understand). So towards the end of method FirstDouble they try and assign local variable array to a new set of elements which fails and the new values of the original caller when displayed are 2,4,6.
Now my confusion is how did the for loop in method FirstDouble modify the original caller firstArray to 2,4,6 if it was passed by value. I thought the value should remain 1,2,3.
Thanks in advance
The key to understanding this is to know the difference between a value type and a reference type.
For example, consider a typical value type, int.
int a = 1;
int b = a;
a++;
After this code has executed, a has the value 2, and b has the value 1. Because int is a value type, b = a takes a copy of the value of a.
Now consider a class:
MyClass a = new MyClass();
a.MyProperty = 1;
MyClass b = a;
a.MyProperty = 2;
Because classes are reference types, b = a merely assigns the reference rather than the value. So b and a both refer to the same object. Hence, after a.MyProperty = 2 executes, b.MyProperty == 2 since a and b refer to the same object.
Considering the code in your question, an array is a reference type and so for this function:
public static void FirstDouble(int[] array)
the variable array is actually a reference, because int[] is a reference type. So array is a reference that is passed by value.
Thus, modifications made to array inside the function are actually applied to the int[] object to which array refers. And so those modifications are visible to all references that refer to that same object. And that includes the reference that the caller holds.
Now, if we look at the implementation of this function:
public static void FirstDouble(int[] array)
{
//double each elements value
for (int i = 0; i < array.Length; i++)
array[i] *= 2;
//create new object and assign its reference to array
array = new int[] { 11, 12, 13 };
}
there is one further complication. The for loop simply doubles each element of the int[] that is passed to the function. That's the modification that the caller sees. The second part is the assignment of a new int[] object to the local variable array. This is not visible to the caller because all it does is to change the target of the reference array. And since the reference array is passed by value, the caller does not see that new object.
If the function had been declared like this:
public static void FirstDouble(ref int[] array)
then the reference array would have been passed by reference and the caller would see the newly created object { 11, 12, 13 } when the function returned.
What a confusing use of terms!
To clarify,
for a method foo(int[] myArray), "passing a reference (object) by value" actually means "passing a copy of the object's address (reference)". The value of this 'copy', ie. myArray, is initially the Address (reference) of the original object, meaning it points to the original object. Hence, any change to the content pointed to by myArray will affect the content of the original object.
However, since the 'value' of myArray itself is a copy, any change to this 'value' will not affect the original object nor its contents.
for a method foo(ref int[] refArray), "passing a reference (object) by reference" means "passing the object's address (reference) itself (not a copy)". That means refArray is actually the original address of the object itself, not a copy. Hence, any change to the 'value' of refArray, or the content pointed to by refArray is a direct change on the original object itself.
All method parameters are passed by value unless you specifically see ref or out.
Arrays are reference types. This means that you're passing a reference by value.
The reference itself is only changed when you assign a new array to it, which is why those assignments aren't reflected in the caller. When you de-reference the object (the array here) and modify the underlying value you aren't changing the variable, just what it points to. This change will be "seen" by the caller as well, even though the variable (i.e. what it points to) remains constant.
idea for you all there with knowledge of .net open sources to implement the logics;
//Sample Code, Illustration;
Method1(params dynamic[] var1) {
var1[0]=new dynamic[3] { 1,2,3 }
}
the var1 is not specified or cannot be ref ?
a usage scenario would be ...
//Sample Code, Illustration;
dynamic[] test = new dynamic[];
Method1( ref test,x,x,x,x );
System.Windows.MessageBox.Show( test[2].ToString() );
to indicate ref only when, not being a parameter specific;
and a ref to array items;
//result is IndexOutOfBounds;
this is only a illustrationm it can be done by returning a array and use like:
test = Method1( test,... );
instead of :
Method1( ref test,x,x,..., ref test[x], ref test2, ... );

Categories

Resources