Is there a reason for array declaration syntax in C#? - 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

Related

how does initializing structs work in c#?

im currently going through a game tutorial in c# and since i dont know almost anything about the language simple stuff looks confusing.
in my class i have something like this:
[Serializable]
public struct TileStruct
{
public TileDataStruct[] Layer;
public byte Type;
public int Data;
public byte DirBlock;
}
public TileStruct[,] Tile;
first question is what does [,] mean here?
second, it is initialized like this:
Tile = new TileStruct[(byteValue), (byteValue)]
1) why are two values passed to TileStruct? Where do they end up?
2) why are the values passed in parentheses?
public TileStruct[,] Tile;
This part declares public variable named Tile. TileStruct[,] means this variable holds a reference to a two dimensional array which contains instances of TileStruct. You can read more about this here.
Tile = new TileStruct[(byteValue), (byteValue)]
This line creates new instance of two dimensional array I've mentioned earlier and assigns it to Tile variable. [(byteValue), (byteValue)] declares size of this array in each dimension. Those values are not passed to TileStruct in any way. There's no need for parentheses around byteValue and deleting them won't change anything.

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!

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.

why don't string object refs behave like other object refs?

string a = "a";
string b = a;
string a = "c";
Why does string b still have the value "a" and not "c"?
As string is an object and not a stack value type, what's with this behaviour?
Thanks
You're pointing the variable to something new, it's no different than if you said
Foo a = new Foo();
Foo b = a;
a = new Foo();
// a no longer equal to b
In this example, b is pointing to what a initially referenced. By changing the value of a, a and b are no longer referencing the same object in memory. This is different than working with properties of a and b.
Foo a = new Foo();
Foo b = a;
a.Name = "Bar";
Console.WriteLine(b.Name);
In this case, "Bar" gets written to the screen because a and b still reference the same object.
Let me start by saying that your choices for variables and data are poor. It makes it very difficult for someone to say "the string a in your example..." because "a" could be the content of the string, or the variable containing the reference. (And it is easily confused with the indefinite article 'a'.)
Also, your code doesn't compile because it declares variable "a" twice. You are likely to get better answers if you ask questions in a way that makes them amenable to being answered clearly.
So let's start over.
We have two variables and two string literals.
string x = "hello";
string y = x;
x = "goodbye";
Now the question is "why does y equal 'hello' and not 'goodbye'"?
Let's go back to basics. What is a variable? A variable is a storage location.
What is a value of the string type? A value of the string type is a reference to string data..
What is a variable of type string? Put it together. A variable of type string is a storage location which holds a reference to string data.
So, what is x? a storage location. What is its first value? a reference to the string data "hello".
What is y? a storage location. What is its first value? a reference to the string data "hello", same as x.
Now we change the contents of storage location x to refer to the string data "goodbye". The contents of storage location y do not change; we didn't set y.
Make sense?
why don’t string object refs behave like other object refs?
I deny the premise of the question. String object refs do behave like other object refs. Can you give an example of where they don't?
Part of what confuses people so much about this is thinking of the following as an append operation:
str1 = str1 + str2;
If string were a mutable type, and the above were shorthand for something like this:
str1.Append(str2);
Then what you're asking would make sense.
But str1 = str1 + str2 is not just some method call on a mutable object; it is an assignment. Realizing this makes it clear that setting a = "c" in your example is no different from assigning any variable (reference type or not) to something new.
The below comparison between code that deals with two List<char> objects and code that deals with two string objects should hopefully make this clearer.
var a = new List<char>();
var b = a; // at this point, a and b refer to the same List<char>
b.Add('a'); // since a and b refer to the same List<char> ...
if (b.Contains('a')) { /* ...this is true... */ }
if (a.Contains('a')) { /* ...and so is this */ }
// HOWEVER...
a = new List<char>(); // now a and b do NOT refer to the same List<char>...
if (b.Contains('a')) { /* ...so this is still true... */ }
if (a.Contains('a')) { /* ...but this is not */ }
Compare this with a slightly modified version of the code you posted:
string a = "a";
string b = a; // at this point, a and b refer to the same string ("a")...
if (b == "a") { /* ...so this is true... */ }
if (a == "a") { /* ...and so is this */ }
// REMEMBER: the below is not simply an append operation like List<T>.Add --
// it is an ASSIGNMENT
a = a + "c"; // now they do not -- b is still "c", but a is "ac"
if (b == "a") { /* ...so this is still true... */ }
if (a == "a") { /* ...but this is not */ }
In .Net, a, b and c are reference to the objects and not the objects themselves. When you reset a, you are pointing this reference to a new memory location. The old memory location and any references to it are unchanged.
I guess the OP thinks string objects to be mutable, so something like var = "content";
would actually store the new character array inside the already existing object.
String is, however, an immutable type, which means that in this case a new string object is created and assigned to var.
See for example:
http://codebetter.com/blogs/patricksmacchia/archive/2008/01/13/immutable-types-understand-them-and-use-them.aspx
It is a misunderstanding because of the builtin string support of c#.
string a = "123"; //The way to write it in C#
string a = new string("123"); //Would be more obvious
The second way to define a is more obvious what happens, but it is verbose.Since strings have direct support from the compiler calling the string constructor is unnecessary.
Writing your example verbose:
string a = new string("a");
string b = a;
string a = new string("c");
Here the behavior is as expected a gets a reference to the new string object assigned. while the reference held by b still points to the old string.

Not able to modify object of struct in loop

I have a List of structure.In the loop i am trying to modify the object's property,which is happening,but when i (Quick look in Visual studio)look into the list object ,the new value is not reflecting.Is it by virtue that the structure's object cannot be modified when in a collection?
I am using generics list with the struct as the type in the list
You mention "modify the object's property" in the context of a struct, but importantly a struct is not an object. Other people have answered as to the issue with structs being copied (and changes discarded), but to take that further the real problem here is that you have a mutable (changeable) struct at all. Unless you are on XNA (or similar) there is simply no need.
If you want to be able to change properties, make it a class:
public class Foo {
public string Bar {get;set;}
}
This is now a reference-type, and your changes (obj.Bar = "abc";) will be preserved through the foreach. If you really want/need a struct, make it immutable:
public struct Foo {
private readonly string bar;
public string Bar { get {return bar; }}
public Foo(string bar) {this.bar = bar;}
}
Now you can't make the mistake of changing the value of a copy; you would instead have to use the indexer to swap the value (list[i] = new Foo("abc");). More verbose (and you can't use foreach), but correct.
But IMO, use a class. Structs are pretty rare, to be honest. If you aren't sure: class.
If you are using a foreach loop you probably got
Compiler Error CS1654
Error Message Cannot modify members of
'variable' because it is a 'read-only
variable type'
This error occurs when you try to
modify members of a variable which is
read-only because it is in a special
construct.
One common area that this occurs is
within foreach loops. It is a
compile-time error to modify the value
of the collection elements. Therefore,
you cannot make any modifications to
elements that are value types,
including structs.
You could however try
struct MyStruct
{
public int i;
}
List<MyStruct> list = new List<MyStruct>
{ new MyStruct { i = 1 }, new MyStruct { i = 2 } };
for(int i = 0; i < list.Count; i++)
{
MyStruct val = list[i];
val.i++;
list[i] = val;
}
EDIT
See also Structs Tutorial
Structs vs. Classes
Structs may seem similar to classes,
but there are important differences
that you should be aware of. First of
all, classes are reference types and
structs are value types.
I THINK i know what the problem might be.
struct Astruct
{
int amember;
}
List < Astruct > listofStructs;
foreach(Astruct A in listofStructs)
{
A.amember = 1337;
}
if this is what you are doing...
when you use structs in c# they are not referenced but copied! so that means the contents of your list is being COPIED to A, so when you change A it doesn't change the value in the list!
to solve this problem (if this is your problem...) either use CLASSES rather than STRUCTS, that way A would be a reference, OR use a manual iterating for loop instead, ie:
for(int i=0;i < listofStructs.Count;i++)
{
listofStructs[i].amember = 1337;
}
alternatively, if you’re using a list, you maybe should use an iterator or something... but the above should definitely fix that problem.
Given the information in your post (although I'd have liked to see the code itself), let me put forth the most probable issue and its fix.
foreach(var s in listOfStructs)
{
s.Property = x;
}
s is assigned to a copy of the actual struct in the collection. s.set_Property is now modifying the copy which is thrown away at the end of the current iteration.
This is because 2 value type variables cannot point to the same instance.
struct1 = new MyStruct(100, 200);
struct2 = struct1; // struct2 is now a copy of struct1
Now to the problem of how do you modify the instances in a collection:
Get the object to modify in a local variable (copy created). Modify it. Now remove the original object and insert the copy. use listOfStructs[i] = modifiedInstance.

Categories

Resources