Propagating changes across un-boxed variables - c#

I just did a little experiment to see if altering an un-boxed variable would propagate changes made to the original source and got two completely different results depending on the types that I used. I am mainly interested in figuring this out for WPF data binding applications in which I bind to objects, cast, change, and hope that the original's update their UIs.
My results were as follows.
Simple types seem to lose their reference to the original source after un-boxing.
Custom types seem to keep their reference.
It seems that I don't have anything to worry about in my scenario of hoping that my WPF UI updates itself after making changes to unboxed bound data contexts; however, not knowing WHY this happens only with complex objects worries me a bit. I do not want my UI to fail on rare or odd occasions I do not know about. Can anyone explain what the heck is mechanically going on back there?
class Program
{
//simple types
private static object sbox1;
private static object sbox2;
private static int svalue1 = 10;
private static int svalue2 = 15;
//custom types
private static MyType cvalue1;
private static MyType cvalue2;
private static object cbox1;
private static object cbox2;
static void Main(string[] args)
{
//Box up the values
sbox1 = svalue1;
sbox2 = svalue2;
//unbox the values to local var
var sunboxed1 = (int)sbox1;
var sunboxed2 = (int)sbox2;
//change the values in the new unboxed vars
sunboxed1 = -10;
sunboxed2 = -15;
//check unboxed values and check original value variables
Console.WriteLine("unboxed1 = " + sunboxed1);
Console.WriteLine("unboxed2 = " + sunboxed2);
Console.WriteLine("value1 = " + svalue1);
Console.WriteLine("value2 = " + svalue2);
//Now try hand at custom types
cvalue1 = new MyType() { Example = "I am cvalue1's original string." };
cvalue2 = new MyType() { Example = "I am cvalue2's original string." };
//now box them up.
cbox1 = cvalue1;
cbox2 = cvalue2;
//now unbox and change the strings
var cunboxed1 = cbox1 as MyType;
var cunboxed2 = cbox2 as MyType;
//change the original strings to see if they propogate to original objects
cunboxed1.Example = "I am cunboxed1's altered string.";
cunboxed2.Example = "I am cunboxed2's altered string.";
//print unboxed and originals values to compare
Console.WriteLine("cunboxed1.Example = " + cunboxed1.Example);
Console.WriteLine("cunboxed2.Example = " + cunboxed2.Example);
Console.WriteLine("cvalue1.Example = " + cvalue1.Example);
Console.WriteLine("cvalue2.Example = " + cvalue2.Example);
Console.ReadKey();
}
}
class MyType
{
public string Example { get; set; }
}
Results from the tester app:
unboxed1 = -10
unboxed2 = -15
value1 = 10
value2 = 15
cunboxed1.Example = I am cunboxed1's altered string.
cunboxed2.Example = I am cunboxed2's altered string.
cvalue1.Example = I am cunboxed1's altered string.
cvalue2.Example = I am cunboxed2's altered string.

What you're seeing is caused by the different handling of value and reference types. In the first example, you are boxing an int. This is wrapped in Int32, a value type, and assigned to your object variable. In your unboxing step, the original Int32 object is copied, because it is a value type, and its value is assigned to your int variable sunboxed1. sbox1 and sunboxed1 hold different values and exist at different memory locations, so no change made to one will affect the other.
In your second example, you are assigning a class to an object variable. This isn't boxing it; you're simply upcasting a reference to your object. When you subsequently downcast it back to MyType with the as keyword, you get a reference to the original object. So, cvalue1 and cunboxed1 hold a reference to the same object.

As dotnetom stated this is more about value vs reference types.
According to MSDN http://msdn.microsoft.com/en-us/library/t63sy5hs.aspx
A data type is a value type if it holds the data within its own memory allocation. Value types include the following:
All numeric data types....
However, for classes:
A reference type contains a pointer to another memory location that holds the data. Reference types include the following: Class types, such as Form.....
With the last line being the most interesting.
A class is a reference type. For this reason, reference types such as Object and String are supported by .NET Framework classes. Note that every array is a reference type, even if its members are value types.
This is why the custom types above changed the original values above after un-boxing. strings themselves are reference types so it it might seem that the reason changes were propogated was due to me using a string as an example and not a numeric type; however, changing the Example property to an int will still change the original source as well and yield the same results.

Related

Beginner: Is there an elegant way to update all copies of an instance?

The following code doesn't update the copy of a inside the array.
int a = null;
int[] numbers = new int[1];
numbers[0] = a;
a = 5; // 5
Console.WriteLine(numbers[0]); // null
Got a programming task requiring to set-up a structure of locations linked by portals between them which isn't possible by just listing the required connections. I'll get references to null that stay null even if I fill an entity later in the code.
Looking for keywords or techniques which might solve my issue.
You could have reference types instead of value types inside array, therefore updating the value of the inner object will also affect the array.
var tab = new MyClass[1];
var obj = new MyClass(5);
tab[0] = obj;
Console.WriteLine(tab[0].Value); // 5
tab[0].Value = 10;
Console.WriteLine(tab[0].Value); // 10
obj.Value = 15;
Console.WriteLine(tab[0].Value); // 15
public class MyClass
{
public MyClass(int value)
{
Value = value;
}
public int Value { get; set; }
}
integers is a value type, as such the actual value is copied. So there is never any 'instance' in your example code, only copies of the value.
You should probably wrap your value in a class, since classes are a reference type to get your desired behavior. This might be useful when you need to share some mutable between multiple components. You can also add an event that is raised whenever the value is changed to let any component that needs the value know that it might need to update something. For example:
public class MyChangeable<T>
{
private T value;
public MyChangeable(T value) => this.value = value;
public T Value
{
get => value;
set
{
this.value = value;
OnChanged(this, value);
}
}
public event EventHandler<T> OnChanged;
}
There is also ref return and ref locals that could do something like your example, but this is mostly intended to get better performance by avoiding copies of large structs, it is not as useful if you want to share values between components.
Arrays are reference types
var a = new int[1];
var numbers = new [] { a };
a[0] = 5;
Console.WriteLine(numbers[0][0]);
You just have to remember that you're one level deeper than you wanted to be/you need to stick a [0] on everything you wouldn't have stuck it on before. It's a bit of a hack, and I'd probably make a class for it like other answers recommend, but stuffing a value type in an array of size 1 can be a useful technique to quickly get reference type behavior out of a value type
ref locals may help you in your task, even if they have strict limitations due to the lifetime of the involved objects, so they could be not applicable as a general solution.
A small example based on your question can be as follows:
int[] array = new int[1];
ref int elem = ref array[0];
elem = 5;
Console.WriteLine(array[0]); // 5
This works not only with value types (including nullable types) but also with reference types.

Difference between Reference Type and Value type in case of string in c#

Ok, So I am a beginner in C# and I learned the concept of Reference Type and Value Type. Also I understood that Value type is on Stack where as Reference types are stored in Heap. And then we need to to manually allocate memory to Reference type and all of that. But I am not able to understand below Behaviour. Please guide me.
Example 1:
var arr1 = new int[3] { 1, 2, 3 }; // memory allocated
var arr2 = arr1; // another variable created but pointing to same memory in Heap
arr2[0] = 2; // value in array 2 changed
System.Console.WriteLine("");
foreach (var item in arr1)
{
System.Console.WriteLine(item);
}
System.Console.WriteLine("------------");
foreach (var item in arr2)
{
System.Console.WriteLine(item);
}
Output as :
arr1: 2,2,3
arr2: 2,2,3
Conclusion: Since both were pointing to same memory location. So, when value in Array 2 is changed the value in Array1 also got affected. So far so good.
Now there is one more reference type which is string.
Consider below Example 2:
var Name = "Mosh";
var FName = Name;
FName = "Hello";
System.Console.WriteLine(Name);
System.Console.WriteLine(FName);
Output as:
Mosh
Hello
Expected Output:
Hello
Hello
Since I changed the value for FName I was expecting the Name value also to be changed as both must be pointing to same memory location. It's one of the simplest question on SO, I am a beginner so bear with me.
In the .Net Framework a String is an immutable reference type.
Since a String does not have a pre-defined memory size (as the value types that can be stored in the Stack), it can grow large (approx. 2 billion Unicode characters), and requires dynamic memory allocation. When a String object is created, the actual value is stored within dynamic memory, the Heap.
Immutable means, it cannot be changed after it has been created. Every change to a string will create a new string. This is why all of the String manipulation methods return a string.
Reference types have some overhead on construction and destruction and
garbage collection, because they are created on the heap. Value types
on the other hand have overhead on method calls (if the data size is
larger than a pointer), because the whole object is copied rather than
just a pointer. Because strings can be much larger than the size of a
pointer, they are designed as reference types. Ref.
In your case: When you assign Name to FName: FName = Name both Strings reference the same Object (as shown in the code sample) that contains the string "Mosh" in the Heap. After FName has ben set to another string value it references a different memory location that stores the new string "Hello". Name keeps pointing to original memory location that stores "Mosh" and remains unchanged.
This behavior of String as value type is less obvious when it is used as a parameter that updates the value in the function. As long as the String parameter is not provided by reference it's original value will not be changed (see sample).
using System;
public class Program
{
public static void Main()
{
var Name = "Mosh";
var FName = Name;
Console.WriteLine(Object.ReferenceEquals(Name,FName));
FName = "Hello";
System.Console.WriteLine(Name);
System.Console.WriteLine(FName);
Console.WriteLine(Object.ReferenceEquals(Name,FName));
TestFunc(Name);
System.Console.WriteLine(Name);
RefFunc(ref FName);
System.Console.WriteLine(FName);
}
public static void TestFunc(string test)
{
test = "after passing";
}
public static void RefFunc(ref string test)
{
test = "after passing";
}
}
Your confusion comes in part because you see both these statements as somewhat equivalent in nature. They are not!
arr2[0] = 2;
FName = "Hello";
In the first case, the array that arr2 is pointing to is modified. But, arr2's reference to that array is unchanged. So both arr1 and arr2 keep pointing to the same array and both see the changes to the array.
In the second case however, it is not the object that FName points to that is being changed. That is to say, we are not modifying the "Mosh" string in any way. Rather, we are changing FName's reference to point a different memory location where the immutable string "Hello" resides in the heap. After this point, FName no longer points to the same memory location as Name. Name keeps pointing to the "Mosh"'s memory location, which remains unchanged.
A string in a reference type yes, but by C#'s design it will more or less behave like other primitives / value types.
To get the effect you're mentioned you would have to specify that a value is a pointer, something similar to: string* PName = Name;
Your question, "Is it safe to say they are pointing at the same location in memory?" I'm not actually sure, though I know that strings do not have a fixed address in memory, so you cannot use "&" or "GetHashCode" like you can to test this on integers or other types.
Edit 1:
Well I'll be a monkey's uncle, you're right. Try this:
Console.WriteLine(Object.ReferenceEquals(Name,FName)

Check for "Value" Types (including types such as strings)

How can I find out whether a variable can be copied such that changing the original will not affect the copy (and vice versa)?
I thought checking its Type's IsValueType property would be enough, but noticed that strings are not considered value types, though a copied string behaves for this purpose, as a value type. Are there any others I have to check for?
EDIT
Yes. I realize a string is immutable. I just meant that off the top of my head it seemed like IsValueType is what I'm looking for. All I want is to be able to have copy = original and then never will a change to the variable original affect the variable copy. This is true for ints and strings and not for Forms for example.
EDIT 2
I'm looking for the likes of strings, ints, decimals, Points, enums, Sizes... As opposed to Forms, StringBuilders...
I don't see a way where you can determine this at runtime for any given type. The only way to accomplish this would be to create collection with all known types that have your desired behaviour. That woould be the built-in value type like int, double and so on + the reference type string.
As I mentioned in the comments you cannot just check for the type's IsValueType property because this would be true for struct's but struct's itself can contain objects. Consider the following code:
class Program
{
static void Main(string[] args)
{
var dataTable = new DataTable();
dataTable.Columns.Add("ABC", typeof(string));
var a = new CustomStruct() { IntValue = 1, DataTable = dataTable };
Console.WriteLine("IsValueType: {0}", a.GetType().IsValueType);
Console.WriteLine();
var b = a;
a.IntValue = 2;
a.DataTable.Columns.Add("DEF", typeof(int));
Console.WriteLine("a.IntValue: {0}", a.IntValue);
Console.WriteLine("a.DataTable.Columns.Count: {0}", a.DataTable.Columns.Count);
Console.WriteLine();
Console.WriteLine("b.IntValue: {0}", b.IntValue);
Console.WriteLine("b.DataTable.Columns.Count: {0}", b.DataTable.Columns.Count);
}
}
public struct CustomStruct
{
public int IntValue;
public DataTable DataTable;
}
The output is:
IsValueType: True
a.IntValue: 2
a.DataTable.Columns.Count: 2
b.IntValue: 1
b.DataTable.Columns.Count: 2
So you see, though CustomStruct is a value type b's DataTable object is the same as a's.
So creating a custom list with know types with the desired behaviour is the easiest way to go.

Class Inside Structure

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.

C# Calling a Method, and variable scope

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

Categories