Suppose I have this code:
struct Normal
{
public float x;
public float y;
}
class NormalContainer
{
public Normal[] Normals
{
get; set;
}
}
class Main
{
void Run( NormalContainer container )
{
Normal[] normals = container.Normals // 1 - see below
normals[5].x = 4; // 3 - see below
container.Normals = normals; // 2 - see below
}
}
Does (1) create a copy of the array or is this a reference to the memory occupied by the array? What about (2) ?
Thanks
Array is a reference type, so you are just copying the reference to the array instance.
An array in C# is a reference type. Items like assignment create copies of the reference vs. the value. At the end of (1) you end up with a local reference to the array stored in container
Note: In C# it's more proper to say "reference to the object" vs. "reference to the memory"
(1) copies the array's reference
(2) same
Array variables are reference types, regardless of their underlying element type, so whenever you assign an array variable to another, you are just copying the reference.
Related
I am having a problem were the reference to an object in a list is lost, this is how I elaborated my code :
PropertyObject[] myProperties = new PropertyObject[200];
var objParent = new Parent();
var objProperty = new PropertyObject();
myProperties[0] = objProperty;
objParent.property = myProperties[0];
Now when I modify objParent.property it does not modify the object in the myProperties array, any workaround? I need this so that I don't have to iterate over the array.
This is how I modify the object :
public void modifyObject(ref Parent objectToModify) {
objectToModify.property.isThisCrazy = true;
}
Then I just invoke the modifyObject method.
structs are meant to be immutable. Assinging a struct to another variable will cause the struct to be copied.
When assigning properties on the one instance, the properties of the other other instance of the struct aren't changed. Hence, you don't see updated in the other reference.
Sample code demonstrating the problem with structs:
struct X
{
public string Y { get; set; }
public X(string y) : this()
{
Y = y;
}
}
X x = new X("abc");
X x2 = x;
x2.Y = "def";
Console.WriteLine(x.Y);
Console.WriteLine(x2.Y);
With classes you'd expected x.Y and x2.Y to be the same, but not with structs.
You write that a "reference to an object" is lost, but a struct has no "reference" to it.
A struct has value-type semantics. So when you assign with =, a copy of the right-hand side is made. You do:
myProperties[0] = objProperty;
This copies the value, and puts a copy inside the 0th entry of the array.
If you later modify the "original" instance objProperty, that change will not be present in the copy held in the array.
This is not really an array issue. The same happens with all struct value assignments. For example:
var objProperty2 = objProperty;
If the original objProperty is mutated afterwards, the copied value objProperty2 will be unaffected. See for example C# Reference type assignment VS value type assignment.
Some people consider mutable structs evil.
I have created an Object array like this. But to assign value to object, I have to instantiate each object at every positions of the array? Why do I need this?
This is My method
StageObject[] StageSplitDate = new StageObject[Stages.Rows.Count];
for (int i = 0; i < Stages.Rows.Count; i++)
{
StageSplitDate[i] = new StageObject();
StageSplitDate[i].StageId = "String Value";
StageSplitDate[i].FromTime = StartTime;
StartTime =StartTime.AddMinutes(Convert.ToDouble(10));
StageSplitDate[i].ToTime = StartTime;
}
return StageSplitDate;
And Object Class
public class StageObject
{
public string StageId { get; set; }
public DateTime FromTime { get; set; }
public DateTime ToTime { get; set; }
}
I have to instantiate each object at every positions of the array?
You are not instantiating the array elements twice. In the first line you instantiated an array StageSplitDate with every element set to null.By default each array (of reference types) element is initialized to null. To use it further you need to instantiate each object in the array as well, otherwise you will get null reference exception.
For C#
Arrays (C# Programming Guide) - MSDN
The default value of numeric array elements are set to zero, and reference elements are set to null.
(Since the question was originally tagged for java)
For JAVA
4.12.5. Initial Values of Variables
Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10):
For all reference types (§4.3), the default value is null.
Your array is an array of StageObject references. The StageObjects themselves don't exist yet. Essentially each entry in the array merely "points" to or "refers" to a StageObject.
Before you call new StageObject(), each array element is null, meaning it's referring to nothing.
Think of an analogy where an array is a bookshelf. If you want a shelf of books, just buying the shelf is only the first step; you then need to buy each book and put it on the shelf. Same idea here: allocating the array gives you an empty container, and then you need to create each object and put it into the container.
Why is it like this? Because an initially-empty array is often what you want -- and even if it isn't, unless your object only has a no-arg constructor, Java wouldn't even know how to construct each object.
new StageObject[Stages.Rows.Count] creates a new array of StageObject references containing Stages.Rows.Count null references. You want each element to point to a StageObject. To do that, you need to create some StageObject instances.
StageObject[] StageSplitDate = new StageObject[Stages.Rows.Count];
The above statement only makes reference array for StageObject which are intialized with null but does not actually initanstiate the objects of StageObject
StageSplitDate[i] = new StageObject();
The above statement is creating object of type StageObject and assigns the reference to StageSplitDate element
Could some one please explain, What happens when a reference type is defined inside the value type.
I write the following code:
namespace ClassInsideStruct
{
class ClassInsideStruct
{
static void Main(string[] args)
{
ValueType ObjVal = new ValueType(10);
ObjVal.Display();
ValueType.ReferenceType ObjValRef = new ValueType.ReferenceType(10);
ObjValRef.Display();
Test(ObjVal, ObjValRef);
ObjVal.Display();
ObjValRef.Display();
Console.ReadKey();
}
private static void Test(ValueType v, ValueType.ReferenceType r)
{
v.SValue = 50;
r.RValue = 50;
}
}
struct ValueType
{
int StructNum;
ReferenceType ObjRef;
public ValueType(int i)
{
StructNum = i;
ObjRef = new ReferenceType(i);
}
public int SValue
{
get { return StructNum; }
set
{
StructNum = value;
ObjRef.RValue = value;
}
}
public void Display()
{
Console.WriteLine("ValueType: " + StructNum);
Console.Write("ReferenceType Inside ValueType Instance: ");
ObjRef.Display();
}
public class ReferenceType
{
int ClassNum;
public ReferenceType(int i)
{
ClassNum = i;
}
public void Display()
{
Console.WriteLine("Reference Type: " + ClassNum);
}
public int RValue
{
get { return ClassNum; }
set { ClassNum = value; }
}
}
}
}
Which outputs:
ValueType: 10
ReferenceType Inside ValueType Instance: Reference Type: 10
Reference Type: 10
ValueType: 10
ReferenceType Inside ValueType Instance: Reference Type: 50
Reference Type: 50
I'm curious to know, after calling the method Test(ObjVal, ObjValRef), how the values of ReferenceType is changed to 50 which resides inside the ValueType whose value is not changed?
I don't know for sure, but the compiler probably separates the code into a separate class and then just enforces the rules required. When you use a value type, the value is copied every time it is passed into a method. The reference to a reference type will get copied, but it refers to the same object. This same reference object will get changed while the value type that was copied will get changed. The original that you passed in will not reflect the changes on the copy.
Because Reference Types are Reference Types and Value Types are Value Types. No matter where they Reside.
And also Value type is not changing neither it is changing the Reference its holding. Its the Reference Type that gets changed(Read my words carefully).
i.e the underlying data at that address gets changed. The reference held by value type is still the same.
Value inside value type is reference, that it is not changed. But value that is pointed by the reference could be easily changed.
Reference types are passed into methods as a pointer, so modifying contents will modify the same location in memory. Value types are passed into methods by sending the value on the call stack.
when programming, it's important to understand that calling a method that takes arguments implies/includes/is the same as assigning values to those arguments. plus:
static void Main(string[] args)
{
ValueType ObjVal = new ValueType(10);
ObjVal.Display();
ValueType.ReferenceType ObjValRef = new ValueType.ReferenceType(10);
ObjValRef.Display();
//call to Test(ObjVal, ObjValRef); replaced by the following 4 lines
ValueType v = ObjVal;
ReferenceType r = ObjValRef;
v.SValue = 50;
r.RValue = 50;
ObjVal.Display();
ObjValRef.Display();
Console.ReadKey();
}
should give the same result as your example above. when you declare ValueType v = ObjVal; you are making a copy of the actual struct object, which means that v is a separate object all together. so changing the values of it's members won't affect ObjVal.
however, ReferenceType r = ObjValRef; makes a copy of a reference. So now there are two references, ObjValRef and r, pointing to the same object. Namely the object created when calling new ValueType.ReferenceType(10);
so when changing members of the object pointed to by any of these two references, this object changes, regardless of which pointer is used to perform the change.
oh, by the by.. a reference is just an address of an object. often this is a 32 bit number, but this changes from language to language, and from processor to processor.
and changing the reference copy in itself, e.g. r = null; won't affect the "original" reference ObjValRef, since r is a copy of ObjValRef, and not ObjValRef itself. it just appears as though they are the same, since they both point to the same object.
you can think of the actual object as a place (a park or some famous building, maybe "white mountain park") and the references as street signs pointing to this place. there can be many street signs pointing to the same place, but this doesn't mean that there are many "white mountain park". and this is the difference between value types and reference types.
From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this. Can someone please explain why I can change the values stored in the int[]?
private void DoIt(){
SearchInfo a = new SearchInfo();
a.Index = 1;
a.Map = new int[] { 1 };
SearchInfo b = new SearchInfo();
b.Index = 1;
b.Map = new int[] { 1 };
ModifyA(a);
ModifyB(ref b);
Debug.Assert(a.Index == 1);
Debug.Assert(a.Map[0] == 1, "why did this change?");
Debug.Assert(b.Index == 99);
Debug.Assert(b.Map[0] == 99);
}
void ModifyA(SearchInfo a) {
a.Index = 99;
a.Map[0] = 99;
}
void ModifyB(ref SearchInfo b) {
b.Index = 99;
b.Map[0] = 99;
}
struct SearchInfo {
public int[] Map;
public int Index;
}
In C#, references are passed by value. An array is not copied when passed to method or when stored in an instance of another class. - a reference to the array is passed. This means a method which recieves a reference to an array (either directly or as part of another object) can modify the elements of that array.
Unlike languages like C++, you cannot declare "immutable" arrays in C# - you can however uses classes like List which have readonly wrappers available to prevent modification to the collection.
From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this.
An array is defined as a collection of variables.
Variables, by definition, can be changed. That is why we call them "variables".
Therefore when you pass an array, you can change the contents; the contents of an array are variables.
Why can I change a struct’s int[] property without specifying “ref”?
Remember, as we discussed before in a different question, you use ref to make an alias to a variable. That is what "ref" is for -- making aliases to variables. (It is unfortunate that the keyword is the confusing "ref" -- it probably would have been more clear to make it "alias".)
From MSDN:
Do not return an internal instance of an array. This allows calling code to change the array. The following example demonstrates how the array badChars can be changed by any code that accesses the Path property even though the property does not implement the set accessor.
using System;
using System.Collections;
public class ExampleClass
{
public sealed class Path
{
private Path(){}
private static char[] badChars = {'\"', '<', '>'};
public static char[] GetInvalidPathChars()
{
return badChars;
}
}
public static void Main()
{
// The following code displays the elements of the
// array as expected.
foreach(char c in Path.GetInvalidPathChars())
{
Console.Write(c);
}
Console.WriteLine();
// The following code sets all the values to A.
Path.GetInvalidPathChars()[0] = 'A';
Path.GetInvalidPathChars()[1] = 'A';
Path.GetInvalidPathChars()[2] = 'A';
// The following code displays the elements of the array to the
// console. Note that the values have changed.
foreach(char c in Path.GetInvalidPathChars())
{
Console.Write(c);
}
}
}
You cannot correct the problem in the preceding example by making the badChars array readonly (ReadOnly in Visual Basic). You can clone the badChars array and return the copy, but this has significant performance implications.
Although your SearchInfo struct is a value type, the .Map field is holding a reference, because Array is a reference type. Think of this reference as the address pointing to the memory location where the array resides.
When you pass an instance of SearchInfo to a method, as you know, the SearchInfo gets copied. And the copy naturally contains the very same address pointing to the very same array.
In other words, copying the struct doesn't make a copy of the array, it just makes a copy of the pointer.
Well, it is passed by reference anyway, like all reference types in C#.
Neither C# nor CLR support constness, unfortunately, so the platform doesn't really know if you are allowed to change it or not. So, it has the reference, it may use it to change the value, and there's nothing to stop it from doing so.
You may see it as a language design bug, btw. It is unexpected for the user.
Why is cards being changed below? Got me puzzled.. understand passing by ref which works ok.. but when passing an Array is doesn't do as I expect. Compiling under .NET3.5SP1
Many thanks
void btnCalculate_Click(object sender, EventArgs e)
{
string[] cards = new string[3];
cards[0] = "old0";
cards[1] = "old1";
cards[2] = "old2";
int betResult = 5;
int position = 5;
clsRules myRules = new clsRules();
myRules.DealHand(cards, betResult, ref position); // why is this changing cards!
for (int i = 0; i < 3; i++)
textBox1.Text += cards[i] + "\r\n"; // these are all new[i] .. not expected!
textBox1.Text += "betresult " + betResult.ToString() + "\r\n"; // this is 5 as expected
textBox1.Text += "position " + position.ToString() + "\r\n"; // this is 6 as expected
}
public class clsRules
{
public void DealHand(string[] cardsInternal, int betResultInternal, ref int position1Internal)
{
cardsInternal[0] = "new0";
cardsInternal[1] = "new1";
cardsInternal[2] = "new2";
betResultInternal = 6;
position1Internal = 6;
}
}
Arrays are reference types which in short means the value of the array is not directly contained within a variable. Instead the variable refers to the value. Hopefully the following code will explain this a bit better (List<T> is also a reference type).
List<int> first = new List<int>()( new int[] {1,2,3});
List<int> second = first;
first.Clear();
Console.WriteLine(second.Count); // Prints 0
In this scenario there is a List<int> created on the first line which is referred to by variable first. The second line does not create a new list but instead creates a second variable named second which refers to the same List<int> object as first. This logic applies to all reference types.
When you pass the variable cards into the method you do not pass a copy of the full array but instead a copy of the variable cards. This copy refers to the same array object as the original cards. Hence any modifications you make to the array are visible through the original reference.
A variable of a reference type does
not contain its data directly; it
contains a reference to its data. When
you pass a reference-type parameter by
value, it is possible to change the
data pointed to by the reference, such
as the value of a class member.
However, you cannot change the value
of the reference itself; that is, you
cannot use the same reference to
allocate memory for a new class and
have it persist outside the block. To
do that, pass the parameter using the
ref or out keyword.
http://msdn.microsoft.com/en-us/library/s6938f28(VS.80).aspx
When you are passing a reference type (like an array) to a method by value, you are passing a copy of it's reference. It's still the same object that is referenced, it doesn't create a copy of the array itself.
When passing parameters to methods, there are three different concepts to be aware of:
By Value vs By Reference parameters
Value vs Reference types
Mutable vs Immutable types
In your example, the string array is a Reference type, is a Mutable type, and is passed By Value. The compiler will always let you change the content of the array because it is Mutable. However, since it is a Reference type, the calling code and the called code both point to the same array contents, so the calling code "sees the changes". The fact that it's passed by value in this case is irrelevant, since although the called code's array variable has indeed been passed a copy of the calling code's variable, they both point to the same location in memory.
As other answers have said, it's because a reference is being passed by value.
I have an article on argument passing in C# which you may find useful, in addition to the answers here.
Arrays are reference types, thus are subject to change.
When you are passing an array as an object it is not copied. The receiving method works with the same instance. In a sense arrays are always passed by ref. When an array as well as an instance of any other reference type is passed as a parameter the receiving method gets its own copy of a reference on the same instance of the type. No copy of the actual object is created.
If you need to pass a copy you have to be explicit about this: create a copy yourself or clone the array. The reason it is not done for you is obvious - copying an array can be expensive, you do not want it unless it is really necessary