In the code below ViewState["L"] stores a List<string>. I create a new instance of List and assign the casted value of a viewstate to it.
List<string> myList = new List<string>();
myList=(List<string>)ViewState["L"];
Response.Write(myList.Equals(ViewState["L"]));// returns True
As you can see, .Equals() method tells me that the Viewstate object and the List object are the same.
Now my question to you guys is how can a List and a Viewstate be a reference to the same object? What does the heap memory at that location actually hold?
Update
The code below demonstrates that any variable that gets assigned a cast value of the viewstate, are all pointing to the same object.
List<string> myList1 = new List<string>();
myList1.Add("apple");
ViewState["L"] = myList1;
List<string> myList2 = new List<string>();
myList2 = (List<string>)ViewState["L"];
List<string> myList3 = new List<string>();
myList3 = (List<string>)ViewState["L"];;
myList3.Add("orange");//Here myList2 gets an orange too !
I think, Thomas is right.
how can a List and a Viewstate be a reference to the same object?
It's not "a ViewState", but an element of the ViewState. ViewState["L"] returns an object which is actually a List<string> (the same one you just assigned to myList)
I suppose you're talking about ASP.NET here.
Consider that ViewState is available on server side, before being trasmitted on client, you reference the exact same object allocated on heap on the server.
Hope this helps.
ViewState is actually an object of type StateBag
StateBag is just a container of other objects.
the ["L"] in ViewState["L"] is an indexer into ViewState that returns some object. In this case that object is a List<string> object
Your Equals() comparison is saying that the reference held by ViewState["L"] is equal to the reference held by myList
Hope that helps
You should read on value/reference types and operator precedence http://msdn.microsoft.com/en-us/library/6a71f45d.aspx.
List<string> myList = new List<string>();
Now previous value of myList is gone and replaced by (ViewState["L"]) cast to List<string>:
myList=(List<string>)ViewState["L"];
Now you compare 2 references to Object type (as the only suitable override is Object.Equals(Object) ) one myList (which holds (ViewState["L"]) ) and another (ViewState["L"]) itself. As result you get true for comparison.
Response.Write(myList.Equals(ViewState["L"]));// returns True
Related
I have a multidimensional array called SensorGetResult. In some cases this array can have a single array in it. If that happens, I must copy this one array and add it again, so I must have 2 arrays now. Then I need to change these array's dateTime property. This is my code:
var helperArray = sensorGet.SensorGetResult[0];
sensorGet.SensorGetResult.Add(helperArray);
sensorGet.SensorGetResult[0].dateTime = end; //It works correctly including this line
sensorGet.SensorGetResult[1].dateTime = start; //At this line both array's dateTime property changes
Why can't I assign dateTime properties to each array individually?
It looks like you are using a reference type for your helperArray.
When the following code executes:
var helperArray = sensorGet.SensorGetResult[0];
sensorGet.SensorGetResult.Add(helperArray);
What actually happens is you take a the first element of SensorGetResult which is a reference to the object (which I believe you intend to copy) and append the reference to the list thus resulting in a list which has two references to the same object in the memory.
If you want it to make a copy of the object, you have to implement that by yourself. Usually this means creating a new object of the same type and copying all the properties.
var objectToCopy = sensorGet.SensorGetResult[0];
var helperArray = new WhatEverTypeIsYourHelperArray {
Property1 = objectToCopy.Property1,
Property2 = objectToCopy.Property2,
// etc.
};
sensorGet.SensorGetResult.Add(helperArray);
But you have to be aware if any of the properties is furthermore a reference type, you need to do this recursively for all the properties.
If WhatEverTypeIsYourHelperArray is type you own, you could utilize Object.MemberwiseClone method and make it all easier for yourself. You can do this by implementing a method like the following. As a note, MemberwiseClone is a protected method hence the need of a new method in your class.
public WhatEverTypeIsYourHelperArray Clone() {
return (WhatEverTypeIsYourHelperArray)this.MemberWiseClone();
}
But even the MemberwiseClone() method doesn't copy reference types for you, rather just copies the pointers to the objects which means that all the properties of reference type of both the original and the cloned object will point to the same objects in the memory.
SensorGetResult row seems to be a reference type.
So when you wrote
var helperArray = sensorGet.SensorGetResult[0];
sensorGet.SensorGetResult.Add(helperArray);
you actually said that new row in SensorGetResult will point to the same object as the first one.
You can implement method like below:
public SensorGetResultRow Clone()
{
return new SensorGetResultRow (this.field1, this.field2, etc...)
//or if you use parameterless constructor
return new SensorGetResultRow ()
{
field1 = this.field1
//etc.
}
}
and use it:
var helperArray = sensorGet.SensorGetResult[0].Clone();
I have a class which has some object fields and I then make a list out of those fields. But I'm confused about how many objects actually exist.
I think the List is a reference type so modifying an object from the list should also modify the field
But if I modify the List & set an item equal to a new object, it only changes the list, not the field
public class MyClass{
public string MyProperty { get; set; } = "Default value";
}
public class TestClass{
private MyClass objectField = new MyClass();
public void run(){
List<MyClass> listOfObjects = new List<MyClass> { objectField };
//Both objectField and listOfObjects[0] have the same value
listOfObjects[0].MyProperty = "Changed value 1st time";
//objectField is "Default value" and listOfObjects[0] is "Changed value 2nd time"
listOfObjects[0].MyProperty = new MyClass();
listOfObjects[0].MyProperty = "Changed value 2nd time";
}
public static void Main() {
TestClass tester = new TestClass();
tester.run();
}
}
Why are there now seemingly 2 objects now? Did the new destroy the reference to the field?
Is there a way to make the field still refer to the new object I create in the list?
This is a simply example, but I have a large list and don't want to have to go and manually update the fields to the values in the list
listOfObjects[0] = new MyClass();
listOfObjects[0].MyProperty = "Changed value 2nd time";
objectField=listOfObjects[0]; //I want to avoid this
Edit (Clarifications)
The real scenario has many object fields of the same base class
I wanted to do the same thing (change property values or instantiate new objects) to all my fields at once so I thought I could just put the fields in a List
I still wanted to be able to refer to the object via it's field name, not just the List index but it appears it can't be done
I'm going to go on a few assumptions here, as your code would not normally compile. Anyways, a generic List<> in C#, when the generic type is a class (reference) type, is a collection of references to those classes, but not a direct pointer to a local object that you put into it.
So basically you have a bunch of class objects hanging out in memory and the list just has references to them. As soon as you new up a new object and REPLACE at one of the indexes, you are replacing the reference to the object in the collection with the new object (not the object in memory itself). The local field still has the reference to the old object.
//E.G.
var objectField = new MyClass();
var listOfObjects = new List<MyClass>{ bjectField };
// Here you are modifying the property of the original object
listOfObjects[0].MyProperty = "1st change";
// Here you are replacing the reference to that object with
// with a reference to a new object, so the properties are totally fresh
// properties go with the old object, a new object has all new fields / properties
// and references
// also, this does not replace the reference to your local field / property
listOfObjects[0] = new MyClass();
// here you are modifying the property on the new object, not the original
listOfObjects[0].MyProperty = "2nd change";
The field, or property belongs to that object. A class in C# is not some structure that you can overlay with a new struct and assume that the fields / properties will just pick up the references to the old fields / properties.
Additionally, passing a local field into a collection does not mean you are giving it a pointer to that field, you are giving it a reference to that object. Even in C++, you would have to specify that you were passing in a pointer to that particular field / property. You cannot do "pointer magic" in C# like you can in C or C++ and change a pointer to a new object (well you can but then you have to do unsafe code, don't do it unless you are interacting with native code structures).
TL;DR; Passing a field into a collection does not mean you are passing a direct pointer to that field into the collection. Therefore, replacing it in the collection does not change your local field.
Can I create an exact duplicate of a list in c#?
List<string> addedAttachments = new List<string>();
addedAttachments = (List<string>)HttpContext.Current.Session["UserFeedbackImage"];
List<string> tempList = addedAttachments;
Stores tempList in a different order
Thanks
You only assign the reference of your first list addadAttachments to a new variable, but don't create a new list.
To create a new list simply call
List<string> tempList = new List<string>(addedAttachments);
The order of the strings in the lists stays the same.
But note that this is only appropriate for immutable types like string. With a list of complex mutable objects, you would add the same objects to the new list, so if you change properties of an object in the old list, the "object in the new list" is also changed (it is the changed object). So you might also need to copy the objects.
To create a copy, try Linq:
List<string> tempList = addedAttachments.ToList();
Since you have a List<string> and string is immutable you can do:
List<string> tempList = addedAttachments.ToList();
If you have a custom object in your list then you should look for cloning.
I have an ArrayList:
ArrayList ReceivedPackets = new ArrayList();
And I have another ArrayList:
ArrayList returnList = ReceivedPackets;
Why does returnList loose it's value when I run this code?
ArrayList ReceivedPackets = new ArrayList(); // ReceivedPackets is empty
ReceivedPackets.Add(1); // Now it has an Integer
ArrayList returnList = ReceivedPackets; // Call-by-Reference (I thought), returnList now has an Integer
ReceivedPackets.clear(); // returnList is empty now. Why?
When you do this:
ArrayList returnList = ReceivedPackets;
You are creating a new variable called returnList, but this variable points to the same in-memory object as ReceivedPackets. There is still only one actual ArrayList, it just has two variables pointing to it. So changes made to one are reflected in both.
How can I do without returnList loosing it's value?
Create a new object. At its simplest, that would look like this:
ArrayList returnList = new ArrayList();
If you also want that object to contain all the values from ReceivedPackets, fortunately ArrayList has a constructor overload which does just that:
ArrayList returnList = new ArrayList(ReceivedPackets);
Now you'd have two objects which should contain copies of the same data. Changes to one would not be reflected in the other.
In the absence of that constructor, ArrayList also has some CopyTo() methods which can be used to copy elements from one to the other. Failing that, you could also manually loop over the source ArrayList and copy elements to the destination ArrayList.
It's possible that this can get pretty confusing if the ArrayList itself contains reference objects. Because those too may have multiple "pointers" to the same in-memory object.
For example, if you create a single Widget object and add it to two ArrayList objects, then any modifications made to the ArrayList objects (adding/removing elements) would be independent, but any modification made to the Widget object would be reflected in both ArrayLists.
The point is that the ArrayList itself is an object, independent of the objects it contains.
So, depending on the full context of what you're doing, your mileage may vary.
ArrayList is a reference type, meaning that if you simply assign some variable to an instance of it, both objects will point to the same location in memory.
If you want to create deep copy, create a new object.
static void Main() {
ArrayList a = new ArrayList() {1,2,3};
var b = a;
var c = new ArrayList(a);
a.Clear();
Console.WriteLine(a.Count); // 0
Console.WriteLine(b.Count); // 0
Console.WriteLine(c.Count); // 3
}
I have something similar to this:
// Declarations:
List<SomeType> list1 = new List<SomeType>();
List<SomeType> list2 = new List<SomeType>();
...
SomeType something = new SomeType("SomeName");
list1.Add(something);
list2.Add(something);
...
list1[indexOfSomething] = new SomeType("SomeOtherName");
And the object in list2 isn't changed... Is that the expected result?
Yes, but nothing's cloned. Before the assignment, the same object is in both lists. After the assignment, you have two unique objects in two lists.
Do This:
list1[indexOfSomething].name = "SomeOtherName";
and the object in list2 will change, too.
// Declarations:
List<SomeType> list1 = new List<SomeType>();
List<SomeType> list2 = new List<SomeType>();
...
SomeType something = new SomeType("SomeName");
list1.Add(something);
list2.Add(something);
Remember, when you add an object to a list, you're really just adding a pointer to the object. In this case, list1 and list2 both point to the same address in memory.
list1[indexOfSomething] = new SomeType("SomeOtherName");
Now you've assigned the element list1 to a different pointer.
You're not really cloning objects themselves, you're copying the pointers which just happen to be pointing at the same object. If you need proof, do the following:
SomeType something = new SomeType("SomeName");
list1.Add(something);
list2.Add(something);
list1[someIndex].SomeProperty = "Kitty";
bool areEqual = list1[someIndex].SomeProperty == list2[someIndex].SomeProperty;
areEqual should be true. Pointers rock!
You are not cloning the object; you are adding a reference to the same object in the two lists. However, your code replaces the reference in one of the lists with a reference to another object, so yes, this is the expected behaviour.
You're replacing the reference in one list with a reference to a new object. If you were to instead change a property of that object, you would see it changed in both places, since the reference would remain the same.
Yes, you're not cloning the object. The object is being added to both lists originally by reference, and then subsequently you're assigned a reference in the list to the new object you're creating.
That is definitely the expected result.
When you pass the 'something' object to Add you are passing by value (c# default), not by reference
Yes that is expected. Only the reference to the object is added. Not the reference itself or a copy.