I'm trying to validate my understanding of how C#/.NET/CLR treats value types and reference types. I've read so many contradicting explanations I stil
This is what I understand today, please correct me if my assumptions are wrong.
Value types such as int etc live on the stack, Reference types live on the managed heap however if a reference type has for example has an instance variable of type double, it will live along with its object on the heap
The second part is what I am most confused about.
Lets consider a simple class called Person.
Person has a property called Name.
Lets say I create an instance of Person in another class, we'll call it UselessUtilityClass.
Consider the following code:
class UselessUtilityClass
{
void AppendWithUnderScore(Person p)
{
p.Name = p.Name + "_";
}
}
and then somewhere we do:
Person p = new Person();
p.Name = "Priest";
UselessUtilityClass u = new UselessUtilityClass();
u.AppendWithUnderScore(p);
Person is a reference type, when passed to UselessUtilityClass -- this is where I go - nuts...the VARIABLE p which is an instance of the Person reference is passed by VALUE, which means when I write p.Name I will see "Priest_"
And then if I wrote
Person p2 = p;
And I do
p2.Name = "Not a Priest";
And write p's name like below I will get "Not a Priest"
Console.WriteLine(p.Name) // will print "Not a Priest"
This is because they are reference types and point to the same address in memory.
Is my understanding correct?
I think there is some misunderstanding going on when people say All objects in .NET are passed by Reference, this doesn't jive based on what I think. I could be wrong, thats why I have come to the Stackers.
Value types such as int etc live on the stack. Reference types live on the managed heap however if a reference type has for example has an instance variable of type double, it will live along with its object on the heap
No, this is not correct. A correct statement is "Local variables and formal parameters of value type which are neither directly in an iterator block nor closed-over outer variables of a lambda or anonymous method are allocated on the system stack of the executing thread in the Microsoft implementation of the CLI and the Microsoft implementation of C#."
There is no requirement that any version of C# or any version of the CLI use the system stack for anything. Of course we do so because it is a convenient data structure for local variables and formal parameters of value type which are not directly in an iterator block or closed-over outer variables of a lambda or anonymous method.
See my articles on this subject for a discussion of (1) why this is is an implementation detail, and (2) what benefits we get from this implementation choice, and (3) what restrictions the desire to make this implementation choice drives into the language design.
http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx
http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx
Person is a reference type, when passed to UselessUtilityClass -- this is where I go - nuts...
Take a deep breath.
A variable is a storage location. Each storage location has an associated type.
A storage location whose associated type is a reference type may contain a reference to an object of that type, or may contain a null reference.
A storage location whose associated type is a value type always contains an object of that type.
The value of a variable is the contents of the storage location.
the VARIABLE p which is an instance of the Person reference is passed by VALUE,
The variable p is a storage location. It contains a reference to an instance of Person. Therefore, the value of the variable is a reference to a Person. That value -- a reference to an instance -- is passed to the callee. Now the other variable, which you have confusingly also called "p", contains the same value -- the value is a reference to a particular object.
Now, it is also possible to pass a reference to a variable, which many people find confusing. A better way to think about it is when you say
void Foo(ref int x) { x = 10; }
...
int p = 3456;
Foo(ref p);
what this means is "x is an alias for variable p". That is, x and p are two names for the same variable. So whatever the value of p is, that's also the value of x, because they are two names for the same storage location.
Make sense now?
Value types such as int etc live on
the stack, Reference types live on the
managed heap however if a reference
type has for example has an instance
variable of type double, it will live
along with its object on the heap
Correct.
You can also describe it as the instance variables being a part of the memory area allocated for the instance on the heap.
the VARIABLE p which is an instance of
the Person reference is passed by
VALUE
The variable is actually not an instance of the class. The variable is a reference to the instance of the class. The reference is passed by value, which means that you pass a copy of the reference. This copy still points to the same instance as the original reference.
I think there is some misunderstanding
going on when people say All objects
in .NET are passed by Reference
Yes, that is definitely a misunderstanding. All parameters are passed by value (unless you use the ref or out keywords to pass them by reference). Passing a reference is not the same thing as passing by reference.
A reference is a value type, which means that everything that you ever pass as parameters are value types. You never pass an object instance itself, always it's reference.
When you pass a person, it is making a copy of the reference - do not confuse this with a copy of the object. In other words, it is creating a second reference, to the same object, and then passing that.
When you pass by ref (with the ref/out keyword), it is passing the same reference to the object that you are using in the caller, rather than creating a copy of the reference.
Maybe this some examples can show you differences between reference types and value types and between passing by reference and passing by value:
//Reference type
class Foo {
public int I { get; set; }
}
//Value type
struct Boo {
//I know, that mutable structures are evil, but it only an example
public int I { get; set; }
}
class Program
{
//Passing reference type by value
//We can change reference object (Foo::I can changed),
//but not reference itself (f must be the same reference
//to the same object)
static void ClassByValue1(Foo f) {
//
f.I++;
}
//Passing reference type by value
//Here I try to change reference itself,
//but it doesn't work!
static void ClassByValue2(Foo f) {
//But we can't change the reference itself
f = new Foo { I = f.I + 1 };
}
//Passing reference typ by reference
//Here we can change Foo object
//and reference itself (f may reference to another object)
static void ClassByReference(ref Foo f) {
f = new Foo { I = -1 };
}
//Passing value type by value
//We can't change Boo object
static void StructByValue(Boo b) {
b.I++;
}
//Passing value tye by reference
//We can change Boo object
static void StructByReference(ref Boo b) {
b.I++;
}
static void Main(string[] args)
{
Foo f = new Foo { I = 1 };
//Reference object passed by value.
//We can change reference object itself, but we can't change reference
ClassByValue1(f);
Debug.Assert(f.I == 2);
ClassByValue2(f);
//"f" still referenced to the same object!
Debug.Assert(f.I == 2);
ClassByReference(ref f);
//Now "f" referenced to newly created object.
//Passing by references allow change referenced itself,
//not only referenced object
Debug.Assert(f.I == -1);
Boo b = new Boo { I = 1 };
StructByValue(b);
//Value type passes by value "b" can't changed!
Debug.Assert(b.I == 1);
StructByReference(ref b);
//Value type passed by referenced.
//We can change value type object!
Debug.Assert(b.I == 2);
Console.ReadKey();
}
}
The term "pass by value" is a little misleading.
There are two things you are doing:
1) passing a reference type (Person p) as a parameter to a method
2) setting a refence type variable (Person p2) to an already existing variable (Person p)
Let's look at each case.
Case 1
You created Person p pointing to a location in memory, let's call this location x. When you go into method AppendWithUnderScore, you run the following code:
p.Name = p.Name + "_";
The method call creates a new local variable p, that points to the same location in memory: x. So, if you modify p inside your method, you will change the state of p.
However, inside this method, if you set p = null, then you will not null out the p outside the method. This behavior is called "pass by value"
Case 2
This case is similar to the above case, but slightly different. When you create a new variable p2 = p, you are simply saying that p2 references the object at the location of p. So now if you modify p2, you are modifying p since they reference the same object. If you now say p2 = null, then p will now also be null. Note the difference between this behavior and the behavior inside the method call. That behavioral difference outlines how "pass by value" works when calling methods
The specifications says nothing about where to allocate value types and objects. It would be a correct C# implementation to say allocate everything on the heap and there Atr situations where values are allocated on the heap other than those you write.
int i = 4;
Func dele = ()=> (object)i;
Will result in (a copy of) i being allocated on the heap because the compiler will make it into a member of a class eventhough it's not declared as such. Other than that you're pretty much spot on. And no everything is not passed as reference. It would be closer to the thruth to state that every parameter was passed by value but still not entirely correct (e.g. ref or out).
Related
How can I access the objects property in this situation?
Araba araba = new Araba();
araba.Renk = "mavi";
araba.fiyat = 12345;
// I created this class and it working normally
ArrayTypedStack asd = new ArrayTypedStack(10);
asd.Push(araba);
object araba2 = asd.Pop();
araba2. //cant access
Here you are assigning the value of asd.Pop() to a variable of the type object.
object is the root of all objects (all objects inherit from it and can be casted to it) and as such has no real information about what it is. It's just like any object in real life is a thing.
The solution here is to declare the araba2 as the type Araba, that will give you access to all the properties on the next line.
I don't know the implementation of the ArrayTypedStack and what the Pop() method looks like (it's return type) so it's possible that this will give you an error, saying that it can't convert an object to the type Araba. This is the type safety implemented in .NET. You have to convince .NET that it's of the type Araba, this can be by casting
Araba araba2 = (Araba)asd.Pop();
this can still give an error on runtime if the object returned from Pop() isn't of the type Araba, in this case you can ask .NET to try to cast it, there are serveral options for this:
object popResult = asd.Pop();
if (popResult is Araba) {
Araba araba2 = (Araba)popResult;
}
// can be written as follows:
if (popResult is Araba araba3) {
araba3.fiyat = 65432;
}
// can also be done as follows
Araba araba4 = asd.Pop() as Araba;
if (araba4 != null) {
araba4.fiyat = 84368;
}
Well, your araba2 variable is of type object. Thus, regardless of the actual type of the instance it contains, through the object variable araba2 you can only access members that are provided by the type object.
To access members provided by the Araba type (and assuming the instance in the araba2 variable is an instance of type Araba), the araba2 variable itself should be of type Araba, or the value of araba2 needs to be cast as Araba.
Thus,
var araba2 = asd.Pop();
or
var araba2 = (Araba) asd.Pop();
with the first example code line above requiring that the return type of the Pop method is Araba (or a type derived from Araba). The latter code line example will work regardless of the return type of Pop as long as the value returned by Pop is an actual Araba instance (or is something that is convertible to an Araba instance).
I'm writing a compare properties two objects of some class, for further listing differences.
Class oldObj, newObj;
//some initiation of above
Class classObject = new Class();
var objectKeys = classObject .GetType().GetProperties().ToList();
objectKeys.ForEach(key => {
var previousKeyValue = key.GetValue(oldObj);
var newKeyValue = key.GetValue(newObj);
if (!Equals) {...}
});
In special cases, newObj or oldObj can be nulls.
My problem is that, in such a case: key.GetValue(null) I'm getting CS0120 exception - "Non-static method requires a target".
Looking at PropertyInfo options (from metadata):
public object? GetValue(object? obj);
I assumed that it will be able to handle such a situation with object being null, with e.g. return null as its value.
Could you please explain if this is proper behaviour of this code, or I'm making something wrong to use null?
In such a case I would probably just before ForEach make some verification if objects are nulls and write separate compare code, handling this situation.
You are misunderstanding the nature of the parameter that is passed to GetValue().
When you pass in an object reference, it means that the reference is an instance property on an instance of an object. If you omit the object reference, you are telling the reflection api that you are trying to access a static member.
I'm asking this out of curiosity and I'm aware about other ways of doing so.
I was wondering, if some method is returning an object of some type and we can modify that object's property directly (on the fly - without taking it's reference into local variable).
Why do we need to take it's reference into local variable to change the object itself?
What logical difficulties can be there at compiler level which restrict programmer to do so.
See example code below:
static Demo StaticDemoInstance;
static void Main(string[] args)
{
//allowed: means I can directly modify property of static instance
// received from method
GetDemo().Name = "UpdateDemo";
//allowed: means I can get instance and overwrite it with other instance
// but not directly from method
Demo d = GetDemo();
d = new Demo("NewCreatedDemo", false);
//not allowed: means I can't do second step directly on method
// question:
// when I can update instance property without receiving instance on local variable
// what possible violation/difficulty (in compiler) will be there so it doesn't allow this
GetDemo() = new Demo("UpdatedDemoFromGetMeth", false);
}
static Demo GetDemo() => StaticDemoInstance ??
StaticDemoInstance = new Demo("StaticDemo", false);
You could always use a Ref return
Starting with C# 7.0, C# supports reference return values (ref
returns). A reference return value allows a method to return a
reference to a variable, rather than a value, back to a caller. The
caller can then choose to treat the returned variable as if it were
returned by value or by reference. The caller can create a new
variable that is itself a reference to the returned value, called a
ref local.
Limitations
There are some restrictions on the expression that a method can return
as a reference return value. Restrictions include:
The return value must have a lifetime that extends beyond the execution of the method. In other words, it cannot be a local variable
in the method that returns it. It can be an instance or static field
of a class, or it can be an argument passed to the method. Attempting
to return a local variable generates compiler error CS8168, "Cannot
return local 'obj' by reference because it is not a ref local."
The return value cannot be the literal null. Returning null generates compiler error CS8156, "An expression cannot be used in this
context because it may not be returned by reference."
A method with a ref return can return an alias to a variable whose value is currently the null (uninstantiated) value or a nullable type
for a value type.
The return value cannot be a constant, an enumeration member, the by-value return value from a property, or a method of a class or
struct. Violating this rule generates compiler error CS8156, "An
expression cannot be used in this context because it may not be
returned by reference."
A really contrived example and not what i recommend, however it does achieve your goals (academically)
Example
static Demo StaticDemoInstance;
...
static ref Demo GetDemo()
{
if (StaticDemoInstance == null)
StaticDemoInstance = new Demo("StaticDemo", false);
return ref StaticDemoInstance;
}
..
GetDemo() = new Demo("UpdatedDemoFromGetMeth", false);
Update
The use of it can be seen with further convoluted example and modifications
Exmaple
static Demo Test()
{
return StaticDemoInstance;
}
...
GetDemo() = new Demo("UpdatedDemoFromGetMeth", false);
var someObject = Test();
someObject= new Demo("Test", false);
Console.WriteLine(StaticDemoInstance.Name);
Console.WriteLine(someObject.Name);
Output
UpdatedDemoFromGetMeth
Test
The Test method (is not ref return) and only giving you a copy of the reference (for lack of better terminology), if you overwrite it, your static variable to StaticDemoInstance doesn't change
var sharedViewModel=new SharedViewModel;
var viewModel1 = new ViewModel1(ref sharedViewModel)
var viewModel2 = new ViewModel2(ref sharedViewModel)
var viewModel3 = new ViewModel3(ref sharedViewModel)
will there be a difference if i do
var viewModel1 = new ViewModel1(sharedViewModel)
var viewModel2 = new ViewModel2(sharedViewModel)
var viewModel3 = new ViewModel3(sharedViewModel)
ViewModel1,ViewModel2,ViewModel3 will be doing changes to the SharedViewModel instance, is there a difference between ref SharedViewModel and SharedViewModel in this case?
Edit:
Example of what will be inside my ViewModel1,ViewModel2,ViewModel3 classes
private SharedViewModel sharedvm;
Public ViewModel(SharedViewModel sharedViewModel)
{
sharedvm=sharedViewModel;
sharedvm.Collection.Add(new object());
}
private doSomthing()
{
sharedvm.Collection.RemoveAt(0);
}
now the question is if i add an object to my sharedvm collection, does that mean that i am adding an object to my sharedViewModel collection?
what about if i call the doSomthing method, will the changes reflect on my sharedViewModel?
Yeah there is a difference.
The value of SharedViewModel can be different because you are passing a reference to a reference (essentially the sharedViewModel variable itself) to the the ViewModel1 constructor.
So if SharedViewModel is changed in the ctor, then it will affect the variable in the calling scope.
By changed I mean in the ViewModel1 ctor you do this:
sharedViewModel = new SharedViewModel()
Perhaps, I wasn't clear enough.
If you've done C/C++ think of it this way.
object *a = new object()
object **b = &a
func(b)
But you still have a high level view because everything is done by the compiler.
EDIT:
First case
public ViewModel(SharedViewModel sharedViewModel)
{
sharedvm=sharedViewModel;
sharedvm.Collection.Add(new object());
}
versus second case
public ViewModel(ref SharedViewModel sharedViewModel)
{
sharedvm=sharedViewModel;
sharedvm.Collection.Add(new object());
}
In this scenario, there is absolutely no difference. The same collection in the heap is being modified. So what happens to the collection can be seen by the calling scope.
The difference occurs when in the first case you do this:
sharedViewModel = new SharedViewModel()
Now you are modifying a completely different object in memory, and the changes applied to that object's collection is not seen by the calling scope because the calling scope references a completely different object.
So usually you never new the argument you just passed in. But if for some reason you do new the argument, then the ref keyword is a way to circumvent the said problem.
No, because instance of SharedViewModel is a reference type sa already passed by as reference.
For me you should't use ref in this case.
Ref could be usefull if you want to pass non-reference type (eg. primitive types as int) as reference, so as a pointer.
As you could read on msdn, about ref
Do not confuse the concept of passing by reference with the concept of reference types. The two concepts are not the same. A method parameter can be modified by ref regardless of whether it is a value type or a reference type. There is no boxing of a value type when it is passed by reference.
Classes are already passed by reference. You don't need ref keyword at all.
Looking at this Microsoft article How to: Write a Copy Constructor (C#) and also this Generic C# Copy Constructor, wouldn't it be best/safe to use a reference to the class instance than to use a plain copy of the instance ?
public class Myclass()
{
private int[] row;
public MyClass(ref MyClass #class)
{
for(int i = 0; i<#class.row.Length;i++)
{
this.row[i] = #class.row[i];
}
}
}
What ref actually means:
void Change(SomeClass instance)
{
instance = new SomeClass();
}
void ChangeRef(ref SomeClass instance)
{
instance = new SomeClass();
}
Later...
SomeClass instance = new SomeClass();
Change(instance);
//value of instance remains unchanged here
ChangeRef(ref instance);
//at this line, instance has been changed to a new instance because
//ref keyword imports the `instance` variable from the call-site's scope
I can't see how this functionality would be useful with respect to a copy constructor.
Object by nature is reference not a value type. I do not see any good reason what extra advantage you would get doing it. But yes you might get into problems because of it, consider this -
You created an object and passed it with reference to couple of classes and those classes are now having access to the address of reference itself. Now I have got all the powers to go and change the reference itself with another object's reference. If here, another class had this object it is actually working on some stale object and other classes can not see what changes are being made and you are in chaos.
I do not see any use of doing it, rather it is dangerous. It does not sounds like a OO way of writing code to me.
The ref keyword is used when a method should be allowed to change the location of a reference. Reference types always pass their reference into a method (but the location of the reference cannot be modified via assignment). Values types pass their value.
See: Passing Parameters
Example:
void PassingByReference(List<int> collection)
{
// Compile error since method cannot change reference location
// collection = new List<int>();
collection.Add(1);
}
void ChangingAReference(ref List<int> collection)
{
// Allow to change location of collection with ref keyword
collection = new List<int>();
collection.Add(2);
}
var collection = new List<int>{ 5 };
// Pass the reference of collection to PassByReference
PassingByReference(collection);
// collection new contains 1
collection.Contains(5); // true
collection.Contains(1); // true
// Copy the reference of collection to another variable
var tempCollection = collection;
// Change the location of collection via ref keyword
ChangingAReference(ref collection);
// it is not the same collection anymore
collection.Contains(5); // false
collection.Contains(1); // false
// compare the references use the default == operator
var sameCollection = collection == tempCollection; // false