C# List<T> internals - c#

What exactly happens when adding an object to a collection such as List?
List<Person> people = new List<Person>();
Person dan = new Person() { Name="daniel", Age=10 };
people.Add(dan);
dan = new Person() { Name = "hw", Age = 44 };
When I execute the above code, the List<Person> peopledoes not get affected by final line.
So I am assuming that the list copies the references of the added object, so when change the reference, the list does not get affected. am I correct?

Well, the code you've shown doesn't actually add anything to the list at all. I assume you meant to have:
people.Add(dan);
in there somewhere?
But yes, the List<T> contains references to objects. It doesn't know about where the references have come from. It's worth being clear about the difference between a variable and its value. When you call:
people.Add(dan);
that copies the value of the argument expression (dan) in this case as the initial value of the parameter within List<T>.Add. That value is just a reference - it has no association with the dan variable, other than it happened to be the value of the variable at the time when List<T>.Add was called.
It's exactly the same as the following situation:
Person p1 = new Person { Name = "Jon" };
p2 = p1;
p1 = new Person { Name = "Dan" };
Here, the value of p2 will still be a reference to the person with the name "Jon" - the second line just copies the value of p1 to p2 rather than associating the two variables together. Once you understand this, you can apply the same logic to method arguments.

Well with that code the List<Person> people should not get affected by the 2nd line either.
Anyway, the List<Person> gets a reference if you use .Add() so if you modify that person later, the person in the list is "modified" too (it's the same person), but if you assign the person to someone else you're not affecting the reference, you're assigning the symbol to a new reference.
e.g.:
List<Person> people = new List<Person>();
Person dan = new Person() { Name="daniel", Age=10 };
people.Add(dan);
/* DanData = { Name="daniel", Age=10 };
* `people[0]` maps to "DanData"
* `dan` maps to "DanData" */
dan.Name = "daniel the first";
string dansNameInList = people[0].Name; /* equals "daniel the first" */
/* DanData = { Name="daniel the first", Age=10 };
* `people[0]` maps to "DanData"
* `dan` maps to "DanData" */
people[0].Name = "daniel again";
string dansName = dan.Name /* equals "daniel again" */
/* DanData = { Name="daniel again", Age=10 };
* `people[0]` maps to "DanData"
* `dan` maps to "DanData" */
dan = new Person() { Name = "hw", Age = 44 };
string dansNameInListAfterChange = people[0].Name /* equals "daniel again" */
string dansNameAfterChange = dan.Name /* equals "hw" */
/* DanData = { Name="daniel again", Age=10 };
* NewData = { Name = "hw", Age = 44 };
* `people[0]` maps to "DanData"
* `dan` maps to "NewData" */

To answer the original question, assuming you intended to add the person to the list before calling the third line:
Yes, the list only stores a reference to the object. In C#, ALL object variables are references.
So when you call new Person() a second time, the reference held by your variable dan is updated to point to the new instance. If the first instance has no reference pointed to it, it will be garbage collected in the next round. If you had added the first instance to the list, the list would still retain it's reference to the first instance.

It's important in .NET programming to have a good understanding of the difference between reference types and value types. This article provides a good overview:
http://www.albahari.com/valuevsreftypes.aspx
In this case, you created two Person objects (Daniel, age 10, and hw, age 44). It's the variables that reference the two objects that created the confusion.
Person dan = new Person() { Name="daniel", Age=10 };
Here, a local variable, dan, is assigned a reference to the newly created (Daniel, age 10) object.
people.Add(dan);
Here, the property people[0] is (indirectly via the List.Add method) assigned a reference to the existing (Daniel, age 10) object.
dan = new Person() { Name = "hw", Age = 44 };
Here, the local variable, dan, is assigned a reference to the newly created (hw, age 44) object. But the property people[0] still holds a reference to the existing (Daniel, age 10) object.

Adding at the end of your code
people[0] = dan;
would point to your new dan object.

Related

C# 9.0 With-expressions. How to use them?

The new C# 9.0 syntax allows for a new kind of expression:
var newPerson = oldPerson with { Age = "21" };
Following questions arise when looking at the previous code line:
Is it a reference or a new object copy?
If it's a reference, what about the inheritance? Consider the following code line:
Person child = new Child{ FirstName = "Jan", LastName = "Brown", IsInKindergarten = false };
Person person = child with { LastName = "Williams" }
Does the compiler allow the person object to inherit the IsInKindergarten property?
In this case var newPerson = oldPerson with { Age = "21" }; it creates a new object that’s a copy of the old one, except with a different age.
Does the compiler allow the person object to inherit the
IsInKindergarten property?
yes, the person will be FirstName = "Jan", LastName = "Williams", IsInKindergarten = false
this syntax about record in c# 9.0 and this is Immutable type indeed all immutable types are creating new object like as struct
for more information about this you can see this
https://channel9.msdn.com/Shows/On-NET/C-9-Language-Features

How to avoid re-memory allocation to an object

The Code below sets the value to an object using reflection. The issue is, it is reallocating the memory to the subfield (Name) of the main object (refObj). Instead of setting the value at the existing memory location.
namespace MemoryAllocation
{
class Name
{
public string name;
public Name(string n)
{
name = n;
}
}
class PersonData
{
public Name PersonName;
public int age;
public PersonData()
{
age = 0;
PersonName = new Name("");
}
}
class ReflectionPractice
{
object localObj;
Type type;
public ReflectionPractice( object refObj)
{
localObj = refObj;
type = refObj.GetType();
}
public void setValueToObject1()
{
FieldInfo fi1 = type.GetField("age");
FieldInfo fi2 = type.GetField("PersonName");
Name personName = new Name("This is first name");
fi1.SetValue(localObj, 34);
fi2.SetValue(localObj, personName);
}
public void setValueToObject2()
{
FieldInfo fi1 = type.GetField("age");
FieldInfo fi2 = type.GetField("PersonName");
Name personName = new Name("This is second name");
fi1.SetValue(localObj, 27);
fi2.SetValue(localObj, personName);
}
}
class Program
{
static void Main(string[] args)
{
object refObj = new PersonData();
Name personName;
ReflectionPractice reflection = new ReflectionPractice(refObj);
reflection.setValueToObject1();
personName = (refObj as PersonData).PersonName;
Console.WriteLine(personName.name);
Console.WriteLine((refObj as PersonData).PersonName.name);
reflection.setValueToObject2();
Console.WriteLine(personName.name);
Console.WriteLine((refObj as PersonData).PersonName.name);
}
}
}
The expected output should be
This is first name
This is first name
This is second name
This is second name
but it is like
This is first name
This is first name
This is first name
This is second name
If inside the ReflectionPractice class, I move the Name object outside the "setValueToObject" method and allocate memory once then the out is correct. But in my problem scenario, I have to allocate memory to Name every time I call "setValueToObject" method. Any solution suggestions will be highly appreciated
Thanks
If you're using C# 7.0 it is quite an easy fix. First to why this happens, if it isn't clear. When you fetch personName the first time, it fetches an address to the object PersonName, which is the same as the address in the refObj. Once you call setValueToObject2, the Object itself is not changed, but a new one is generated at a new address. The address is then assigned to the refObj.PersonName, but your local reference does not know any of this and still points to the initial object, which is the correct and expected behaviour.
To change this and explicitly follow changes to the source at refObj.PersonName, you'll need to declare the local variable personName as a ref-Variable. personName will no longer point to the Object itself, but to refObj.PersonName and whatever is behind that Variable, so it will also Update when you change that Variable.
A working example would look like this:
object refObj = new PersonData();
ReflectionPractice reflection = new ReflectionPractice(refObj);
reflection.setValueToObject1();
ref Name personName = ref (refObj as PersonData).PersonName;
Console.WriteLine(personName.name);
Console.WriteLine((refObj as PersonData).PersonName.name);
reflection.setValueToObject2();
Console.WriteLine(personName.name);
Console.WriteLine((refObj as PersonData).PersonName.name);
Some more in-depth explanation:
When you assign an Object to a Variable, you indeed assign a reference to the Object not the Value of the Object itself. This reference is a Number, wich tells us where to look for the Data of the Object. So if I say reflection.setValueToObject1(), a new Object gets generated at Address 1234 for example. This number is what the Variable refObj.PersonName will contain, you'll never see that number though. When you assign a Variable with a reference to that new object, the only thing done is to copy that number into the new Variable. So after you say personName = refObj.PersonName, personName now also holds the Address 1234 and thus points to the same Object as refObj.PersonName.
As we can see, if we set refObj.PersonName.Name = "Test" the programm will first look into refObj.PersonName and take that Address. It then goes to said Address and changes the Value of Name. The same happens if you change personName.Name. First it looks up the address in the Variable, goes to that address and changes the field Name. This is why you'll see the Name change in both Variables in this case, and this it what "reference-type" means (A value-type will create a copy, so this won't happen).
But; when you create a new Object, you also create a new Address for the Object to live at - e.g. 4567. That is what the new-keyword does: allocate some memory and create a new object there. This Address is now assigned to refObj.PersonName, but not personName (as the Assignment clearly only happens on the refObj). So personName still has the Address 1234 and therefore still points to the old Object.
What ref does: When you create the refObj, it itself (and all fields) will have a certain Address in Memory. Let's say, refObj is at 9900, and its field refObj.PersonName is at 9999. When you say personName = refObj.PersonName, the program looks what Address is stored inside refObj.PersonName (1234) and copies it to personName, but when you say ref personName = ref refObj.PersonName, it takes the Address of the field itself and copies that. So now personName has the value 9999 instead. Whenever you access personName now, it first looks at Address 9999 and then follows that to whichever Address it contains (1234 or 4567). This is why it will update as well when you change refObj.PersonName.
Or, if you're more of the visual type, this is what happens:
refObj.PersonName = new Name("Name 1")
personName = refObj.PersonName
refObj.PersonName = new Name("Name 2")
Compare it to what happens when you use the ref-keyword:
ref personName = ref refObj.PersonName
refObj.PersonName = new Name("Name 2")
I hope this helps to clear this up a little bit :)
The key here is this part of your code:
personName = (refObj as PersonData).PersonName;
Console.WriteLine(personName.name);
Console.WriteLine((refObj as PersonData).PersonName.name);
reflection.setValueToObject2();
Console.WriteLine(personName.name);
Console.WriteLine((refObj as PersonData).PersonName.name);
here you assign the PersonName of the first call to the local variable personName. As you never assign anything different to personName it will allways point to the exact same instance, which is the Name-object of your first call. When calling setValueToObject2 you just create a completely new instance of the Name-class which has no relation to the first one at all. Any modification on this instance therefore is not reflected on the first instance and thus also not within personName.
Thus personName allways reflects the very first Name-instance. (reoObj as PersonData).PersonName on the other hand points to the actual (second) one.
You can easily fix that by re-assigning personName:
personName = (refObj as PersonData).PersonName;
Console.WriteLine(personName.name);
Console.WriteLine((refObj as PersonData).PersonName.name);
reflection.setValueToObject2();
personName = (refObj as PersonData).PersonName; // get the new instance
Console.WriteLine(personName.name);
Console.WriteLine((refObj as PersonData).PersonName.name);
var refObj = new PersonData();
/* You have only a single Name object
* There is a single reference to it
*/
var reflection = new ReflectionPractice(refObj);
reflection.setValueToObject1();
/* You have two Name objects
* Where the name is "" there is no reference anymore
* Where the name is "This is first name" there is a single reference
*/
var personName = (refObj as PersonData).PersonName;
/* You have two Name objects
* Where the name is "" there is no reference anymore
* Where the name is "This is first name" there are two references
*/
reflection.setValueToObject2();
/* You have three Name objects
* Where the name is "" there is no reference anymore
* Where the name is "This is first name" there is one reference (personName variable)
* Where the name is "This is second name" there is one reference
*/
That's why your second Console.WriteLine(personName.name); print the "this is first name".
Setting values in this way fixed the issue. #CShark
public void setValueToObject1()
{
FieldInfo fi1 = type.GetField("age");
FieldInfo fi2 = type.GetField("PersonName");
fi1.SetValue(localObj, 34);
TypedReference reference = __makeref(localObj);
object obj = fi2.GetValueDirect(reference);
Type localtype = obj.GetType();
FieldInfo filocal = localtype.GetField("name");
object o = "first name";
filocal.SetValueDirect(__makeref(obj),o);
fi2.SetValue(localObj, obj);
}
public void setValueToObject2()
{
FieldInfo fi1 = type.GetField("age");
FieldInfo fi2 = type.GetField("PersonName");
TypedReference reference = __makeref(localObj);
object obj = fi2.GetValueDirect(reference);
Type localtype = obj.GetType();
FieldInfo filocal = localtype.GetField("name");
object o = "second name";
filocal.SetValueDirect(__makeref(obj), o);
fi2.SetValue(localObj, obj);
}

What happens when a variable is assigned with an object reference variable with both having similar types

I have a doubt on how reference types actually work.
I have a class Person with two properties Name and Age. I am creating an object of Person class (objPerson1), assigning some values to both the properties and assigning that object to another of type Person (objPerson2). Now the question is after assigning when I change the Name and Age property and print them both the object shares same Name and Age which is fine as they are reference type.But when I assign null value to object itself then other object doesn't get nullified.Below is the code
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void Main(string[] args)
{
Person objPerson1 = new Person();
objPerson1.Name = "Tom";
objPerson1.Age = 10;
Person objPerson2 = objPerson1;
objPerson2.Name = "Jerry";
objPerson2.Age = 15;
Console.WriteLine($" Person1-{objPerson1.Name},{objPerson1.Age} and Person2-{objPerson2.Name},{objPerson2.Age}");
//Above line prints Person1-Jerry,15 and Person2-Jerry,15
//which is right as both are sharing same address.But when I wrote following code it confused me alot.
}
public static void Main(string[] args)
{
Person objPerson1 = new Person();
objPerson1.Name = "Tom";
objPerson1.Age = 10;
Person objPerson2 = objPerson1;
objPerson2 = null;
//After executing above line objPerson2 was null but objPerson1 were still having the values for Name and Age.
}
As they are reference type and both pointing to same address if I assign null to objPerson2 ,objPerson1 should also be null and vice-versa.Correct me if I'm wrong
A bit simplified, but hopefully sufficient for you to understand:
Person objPerson1 = new Person();
Heap: memory allocated for object
Stack: objPerson1 = address of the heap object
objPerson1.Name = "Tom";
objPerson1.Age = 10;
Heap: is being filled with values.
Stack: unchanged (still the same address)
Person objPerson2 = objPerson1;
Stack: another variable gets the same address
Heap: unchanged
objPerson2 = null;
Stack: the variable objPerson2 gets the value 0x00000000.
Note that objPerson1 still has the address of the heap and the object on the heap still exists. So objPerson1 still "works".
objPerson2 is only a pointer to the memory allocated by the initialization of objPerson1. Assigning null to objPerson2 removes this pointer. objPerson1 still points to that memory therfore it holds it's value and does not become null once objPerson1 does.

C# Why create multiple references to a single object?

Situation: I recently came across an article where an employer was asking entry-level candidates to solve a complex reference problem (not shown), as well as questions pertaining to the stack and managed heap. I have devoted a bit of time to learning these concepts for personal understanding, but was not aware that these are considered 'entry-level' knowledge. Being a CIS major apposed to CS (huge difference I know) these concepts are not taught.
Question Why would a developer assign an object reference to another reference? More succinctly, why would a developer ever flip flop dozens of references around as described in interview scenarios? Is this simply a matter of testing subject matter comprehension, or is this 'reference flip-flopping' a practice used in "everyday" development?
using System;
namespace QuickConsoleTesting
{
class Program
{
static void Main()
{
//Instantiate two new Person objects on the heap
Person person1 = new Person() { Name = "Jim" };
Person person2 = new Person() { Name = "Todd" };
Person person3 = person1;
Person person4 = new Person() { Name = "Julie" };
//Flip-flop reference variables
person4 = person2;
person1 = person3;
//Display results
Console.WriteLine(person1.Name);
Console.WriteLine(person2.Name);
Console.WriteLine(person3.Name);
Console.WriteLine(person4.Name);
/* ======================================
* Results displayed: Jim, Todd, Jim, Todd
* ===================================== */
//Hold console window
Console.Read();
}//END OF MAIN
}//END OF PROGRAM
class Person
{
private string name = "";
public string Name
{
get { return name; }
set { name = value; }
}
}//END OF PERSON
}//END OF NAMESPACE
These sort of questions are there to test if a candidate understands the difference between a reference variable and a value variable. The supplied scenario (as is) will almost never happen in Real World (tm) code. But, confusion resulting in not understanding why this code snippet does what it does can and does result in a lot of bugs, especially when there are various functions working on the same data.
imagine a class
class Person
{
pubic string Name;
}
With pass by value which is default
Person p=new Person();
//p contains the address of the newly allocated person
change(p);
//p is passed by value so the address within p would get copied into p1 which is a method parameter of change method
public void change(Person p1)
//p1 and p are separate variables containing address of person object
{
p1.Name="SO";
//changes name of p1 and p
p1=null;
//this makes p1 null not p since p and p1 are separate copies pointing to person object
}
With reference
change(ref p);
//p is now passed by reference so p1 is p
public void change(ref Person p1)//p1 and p are same
{
p1.Name="SO";
p1=null;//this makes p and p1 null
}
I am not sure exactly what you're asking, there are many reasons a developer might store the same reference in multiple variables, but that all depends on the code. Remember there is still only one place that the object lives on in the heap, but could have many references to it (and thats where Managed Garbage Collector comes in to clean up objects no longer referenced)
Obviously your example is simply bad code. These types of questions are akin to the C++ pointer questions. C# as a manged language has tried to stay away from pointers, but it is still important to understand the differences between value types and reference types. This is mostly what these questions are designed for.

How can I break inside an C# automatic constructor block?

I was wondering if there are any way to put break point inside an automatic constructor/object initializer block?
Example:
var x = new Person()
{
Name = 'John',
Age = DateTime.Now - Birthdate
}
I want to put breakpoint on the 4th line. This is very helpful when setting like 150 fields with different logic for each property and the type you are creating an instance of is not under your control (e.g. EF4 entity), therefore you cannot create a custom constructor. Any ideas?
A workaround you can use for this issue is writing the code like this to ease your debugging:
var x = new Person();
x.Name = "John";
x.Age = DateTime.Now - Birthdate;
Wrap the value on a line where you want a breakpoint in a self calling function:
var x = new Person() {
Name = new Func<string>(() =>"John").Invoke(),
Age = DateTime.Now - Birthdate
};
Now you will be able to "step into" it. It won't be of much use, though, as x will remain null until the end of the block.
If Name property is not automatic you can put a breakpoint inside set of that property.
If your doing it that way then you can't. You can out a breakpoint on the entire block and step through it using F11.
Why dont you do the following
Person p = new Person();
p.Name = "John";
p.//Blah

Categories

Resources