Reference types as parameters - c#

So I was reading Jon Skeet's C# in depth and came across some myths like Reference types are always passed by ref, So I decided to do a little experiment myself.
As you can see in the following code I have a simple Car class with one property which is initialized to 500 when the constructor is called. I also have the NullIt function which assigns null to the parameter value and a SpeedUp method which just changes the Speed property value.
Examining the main method you can see I instantiate a Car object, then I pass the object to the static SpeedUp method and the Speed value changes to 1000 but when I'm passing it to the also static NullIt method the object remains intact. From this the only thing I can assume is that the object is passed by value and the fields / properties are passed by reference. Is this right?
I know that if I pass it using the ref keyword will return null.
class Program
{
static void Main(string[] args)
{
Car c = new Car();
Car.SpeedUP(c);
Car.NullIt(c);
}
class Car
{
public int Speed { get; set; }
public Car() { Speed = 500; }
public static void SpeedUP(Car c)
{
c.Speed = 1000;
}
public static void NullIt(Car c)
{
c = null;
}
}
}

From this the only thing I can assume is that the object is passed by
value and the fields / properties are passed by reference. Is this
right?
Not really. Object's address is passed by value.
So when you do:
Car.SpeedUP(c);
Now your parameter of method SpeedUp and your field c in caller, both point to the same location in memory. Thus changing the property works.
But for your call:
Car.NullIt(c);
Your method parameter c and caller's c both points to same location. But since you assign null to your parameter c , now it is not pointing to any memory location, but the original/caller's c still points to the same memory location.
Consider the following:
When you pass parameter to your method then two references in memory would be pointing to the same address like:
But when you assign null it doesn't change the other reference.
The first reference (in caller) still points to the same location, only the method parameter is now pointing to null.

When you call NullIt() you are passing the value of a reference to your instance of Car. You then change this value to null. However, the original copy of that value remains intact. Exactly the same way passing the value of an int works - you can modify your local copy without affecting the "original".
If you were to change that to NullIt(ref Car c), you would be passing a reference to the reference, and hence setting it to null would set the original value of the reference to null. That last part can be a bit of a mind bender, but it's so rarely necessary (if ever) that you don't need to worry too much about it.

From this the only thing I can assume is that the object is passed by value and the fields / properties are passed by reference. Is this right?
While the observed effect may look like this, the way you describe it has some incorrect implications: The fields/properties are not "passed by reference" in a way that there is a reference to each field/property. It is rather that the reference to the object is passed by value.
That is why by accessing any member of the object, or the object itself, you are accessing the very same instance you passed into the method, not a copy thereof.
However, the variable c itself is a reference, and that reference is passed by value. That is why, in your methods, you cannot change that reference by assigning a new value and expect that the variable c itself now has a new value (in your case null).

It IS a bit confusing, because the word reference is overloaded (has two subtly different meanings).
When describing types as either value types or reference types. it means one thing,
Whether the data for the state of an object of that type is stored on the stack, (which is a section of memory that methods have access to) or whether it is stored on another section of memory called the Heap, and only the address of that section of heap is then stored on the stack, allowing code to only access the object indirectly.
When describing whether parameter values are passed to a method by value or by reference, otoh, it means something different. It means whether the actual value of the parameter is [copied and] passed to the method, or whether the address of the parameter value's memory slot is passed.
So you can actually have four combinations here:
Pass a value type by value - The value is copied and passed to
the method. The method cannot change the source value.
Pass a reference type by value. The address of the reference type
(which is on the Heap) is copied and passed. The method cannot
change the address in the source variable, but it CAN change the
data on the HEAP that the address points to.
Pass a value type by reference. The method gets the address of the
source object, (on the stack) and can change that source value.
Pass a reference type by reference. The method gets the address of
the variable (on the stack) that contains the address of the object
itself (on the Heap). The method can change the data in the source
object, AND CAN ALSO CHANGE WHICH OBJECT (ON THE HEAP) THE SOURCE
VARIABLE POINTS TO)

Related

c# type References (vs C)

How c# references work if, classes are references
class1 a = new class1();
so address named "a" contains
address of the object indicating mem[0] ,So it's a pointer
why
method(class1 a);
copies value of object to a local method instance and not address of mem[0]?
does it implicitly de-reference (*) a?
if so ,then ref modifier cancels it?
lets say a class defines a type of an address to addresses that point to various points of an object. i still cant get to the end of it...
why method(class1 a) copies value of object to a local method
This is a wrong assumption. The method parameter a contains a reference to the object. If you use method(ref class1 a), then you get a reference to the variable passed to the method, which in turn contains a reference to the object
Given
class1 a = new class1();
method(ref a);
In the method, you could assign a new object to the parameter and this would change a!
void method(ref class1 b)
{
b = new class1(); // This changes a!
}
If the ref keyword is missing, the method gets a copy of the reference (not a copy of the object!)
void method(class1 b)
{
b = new class1(); // This does NOT change a.
// But
b.IntProperty = 5; // This changes a property of a.
}
In C# you don't have to use *. C# knows which types are reference and which ones are value types and treats them accordingly.
For a normal parameter:
For value types: a copy of the value is passed.
For reference types: a copy of the value is passed (yes!). The value just happens to be a reference (or null). I.e., no object is copied.
For ref parameters:
For value types: a reference to the variable containing the value is passed.
For reference types: a reference to the variable containing a reference (or null) is passed.
In other words, for ref parameters, the parameter name is just an alias for the variable used in the method call.
If you find this confusing, it helps to configure the colors in the editor to help to differentiate between reference and value types. In Visual Studio: Go to menu Tools > Options..., then Environment > Fonts and Colors and change the color of User Types - Structures (i.e. of value types) to display as a different color as classes (I am using Olive). There are a few other User Types you can change (I am using Red for delegates, a dark Orange for enums, Purple for interfaces and a kind of neon green for type parameters.
Yes you may want to think about C# class variables as (safe) C pointers, in this sense. They just don't allow you to manipulate where they point in memory (the run-time is even allowed to re-allocate and move them).
If your class1 is a class type (as opposed to a struct type or ValueType), then you are however not correct that method will copy the whole a object. It will instead act as if you had passed a pointer in C. But just like in C, *p1==*p2 and p1==p2 but &p1!=&p2
Since class variables store mere references (similar to C pointers), if method mutates the object referred by a, these mutations will remain after method returns. Passing a class variable by ref is then analogous to passing a pointer to a pointer in C; but it can hardly ever be a good design idea in C#.
This is how class variables behave (including strings). However there are also value types (all basic types except string and object, and structs) which are copied when assigned or passed to methods, unless passed with a qualifier such as ref or out.
Further reading:
Value vs Reference Types
MSDN: Reference types
MSDN: Value types
You will have to understand how methods are called and how objects are allocated in the memory.
All class types are of reference types in C# - inheriting from System.Object.
Supports all classes in the .NET Framework class hierarchy and
provides low-level services to derived classes. This is the ultimate
base class of all classes in the .NET Framework; it is the root of the
type hierarchy.
Reference: MSDN Documentation of System.Object
Meaning, they would be allocated in heap. Their reference would be copied to some place. The variable holds that place where the reference is copied.
In case of method call, the address of an object is copied to call stack. It is pointing to the same address.
So if you change any property (of value type) of the class, you will still be able to access the changed value in the caller method - even though you don't use ref keyword.
void Method(Class A)
Technically, ref keyword provides same address location - instead of copying this address to new location.
Hope this answers your query.

Why does setting a base class equal to a derived type only work within scope of where it is set?

I found it difficult to come up with a descriptive enough title for this scenario so I'll let the code do most of the talking.
Consider covariance where you can substitute a derived type for a base class.
class Base
{
}
class Derived : Base
{
}
Passing in typeof(Base) to this method and setting that variable to the derived type is possible.
private void TryChangeType(Base instance)
{
var d = new Derived();
instance = d;
Console.WriteLine(instance.GetType().ToString());
}
However, when checking the type from the caller of the above function, the instance will still be of type Base
private void CallChangeType()
{
var b = new Base();
TryChangeType(b);
Console.WriteLine(b.GetType().ToString());
}
I would assume since objects are inherently reference by nature that the caller variable would now be of type Derived. The only way to get the caller to be type Derived is to pass a reference object by ref like so
private void CallChangeTypeByReference()
{
var b = new Base();
TryChangeTypeByReference(ref b);
Console.WriteLine(b.GetType().ToString());
}
private void TryChangeTypeByReference(ref Base instance)
{
var d = new Derived();
instance = d;
}
Further more, I feel like it's common knowledge that passing in an object to a method, editing props, and passing that object down the stack will keep the changes made down the stack. This makes sense as the object is a reference object.
What causes an object to permanently change type down the stack, only if it's passed in by reference?
You have a great many confused and false beliefs. Let's fix that.
Consider covariance where you can substitute a derived type for a base class.
That is not covariance. That is assignment compatibility. An Apple is assignment compatible with a variable of type Fruit because you can assign an Apple to such a variable. Again, that is not covariance. Covariance is the fact that a transformation on a type preserves the assignment compatibility relationship. A sequence of apples can be used somewhere that a sequence of fruit is needed because apples are a kind of fruit. That is covariance. The mapping "apple --> sequence of apples, fruit --> sequence of fruit" is a covariant mapping.
Moving on.
Passing in typeof(Base) to this method and setting that variable to the derived type is possible.
You are confusing types with instances. You do not pass typeof(Base) to this method; you pass a reference to Base to this instance. typeof(Base) is of type System.Type.
As you correctly note, formal parameters are variables. A formal parameter is a new variable, and it is initialized to the actual parameter aka argument.
However, when checking the type from the caller of the above function, the instance will still be of type Base
Correct. The argument is of type Base. You copy that to a variable, and then you reassign the variable. This is no different than saying:
Base x = new Base();
Base y = x;
y = new Derived();
And now x is still Base and y is Derived. You assigned the same variable twice; the second assignment wins. This is no different than if you said a = 1; b = a; b = 2; -- you would not expect a to be 2 afterwards just because you said b = a in the past.
I would assume since objects are inherently reference by nature that the caller variable would now be of type Derived.
That assumption is wrong. Again, you have made two assignments to the same variable, and you have two variables, one in the caller, and one in the callee. Variables contain values; references to objects are values.
The only way to get the caller to be type Derived is to pass a reference object by ref like so
Now we're getting to the crux of the problem.
The correct way to think about this is that ref makes an alias to a variable. A normal formal parameter is a new variable. A ref formal parameter makes the variable in the formal parameter an alias to the variable at the call site. So now you have one variable but it has two names, because the name of the formal parameter is an alias for the variable at the call. This is the same as:
Base x = new Base();
ref Base y = ref x; // x and y are now two names for the same variable
y = new Derived(); // this assigns both x and y because there is only one variable, with two names
Further more, I feel like it's common knowledge that passing in an object to a method, editing props, and passing that object down the stack will keep the changes made down the stack. This makes sense as the object is a reference object.
Correct.
The mistake you are making here is very common. It was a bad idea for the C# design team to name the variable aliasing feature "ref" because this causes confusion. A reference to a variable makes an alias; it gives another name to a variable. A reference to an object is a token that represents a specific object with a specific identity. When you mix the two it gets confusing.
The normal thing to do is to not pass variables by ref particularly if they contain references.
What causes an object to permanently change type down the stack, only if it's passed in by reference?
Now we have the most fundamental confusion. You have confused objects with variables. An object never changes its type, ever! An apple is an object, and an apple is now and forever an apple. An apple never becomes any other kind of fruit.
Stop thinking that variables are objects, right now. Your life will get so much better. Internalize these rules:
variables are storage locations that store values
references to objects are values
objects have a type that never changes
ref gives a new name to an existing variable
assigning to a variable changes its value
Now if we ask your question again using correct terminology, the confusion disappears immediately:
What causes the value of a variable to change its type down the stack, only if it's passed in by ref?
The answer is now very clear:
A variable passed by ref is an alias to another variable, so changing the value of the parameter is the same as changing the value of the variable at the call site
Assigning an object reference to a variable changes the value of that variable
An object has a particular type
If we don't pass by ref but instead pass normally:
A value passed normally is copied to a new variable, the formal parameter
We now have two variables with no connection; changing one of them does not change the other.
If that's still not clear, start drawing boxes, circles and arrows on a whiteboard, where objects are circles, variables are boxes, and object references are arrows from variables to objects. Making an alias via ref gives a new name to an existing circle; calling without ref makes a second circle and copies the arrow. It'll all make sense then.
This is not an issue with inheritance and polymorphism, what you're seeing is the difference between pass-by-value and pass-by-reference.
private void TryChangeType(Base instance)
The preceding method's instance parameter will be a copy of the caller's Base reference. You can change the object that is referenced and those changes will be visible to the caller because both the caller the callee both reference the same object. But, any changes to the reference itself (such as pointing it to a new object) will not affect the caller's reference. This is why it works as expected when you pass by reference.
When you call TryChangeType() you are passing a copy of the reference to "b" into "instance". Any changes to members of "instance" are made in the same memory space still referenced by "b" in your calling method. However, the command "instance = d" reassigns the value of the memory addressed by "instance". "b" and "instance no longer point to the same memory. When you return to CallChangeType, "b" still references the original space and hence Type.
TryChangeTypeByReference passes the a reference to where "b"'s pointer value is actually stored. Reassigning "instance" now changes the address that "b" is actually pointing to.
We know that class are reference types, so in general when we are passing a type, we are passing a reference but there's a difference between passing just b and ref b, which can be understood as:
In first case 1 it is passing reference by value, which means creating a separate pointer internally to the memory location, now when base class object is assigned to the derived class object, it starts pointing to another object in the memory and when that method returns, only the original pointer remains, which provides the same instance as Base class, when the new pointer created is off for garbage collection
However when object is passed as ref, this is passing reference to a reference in memory, which is like pointer to a pointer, like double pointer in C or C++, which when changes actually changes the original memory allocation and thus you see the difference
For first one to show the same result value has to be returned from the method and old object shall start pointing to the new derived object
Following is the modification to your program to get expected result in case 1:
private Base TryChangeType(Base instance)
{
var d = new Derived();
instance = d;
Console.WriteLine(instance.GetType().ToString());
return instance;
}
private void CallChangeType()
{
var b = new Base();
b = TryChangeType(b);
Console.WriteLine(b.GetType().ToString());
}
Following is the pictorial reference of both the cases:
When you do not pass by reference, a copy of the base class object is passed inside the function, and this copy is changed inside the TryChangeType function. When you print the type of the instance of the base class it is still the of the type "Base" because the copy of the instance was changed to "Derived" class.
When you pass by referece, the address of the instance i.e. the instace itself will be passed to the function. So any changes made to the instance inside the function is permanent.

Why is the original object changed after a copy, without using ref arguments?

At work we were encountering a problem where the original object was changed after we send a copy through a method. We did find a workaround by using IClonable in the original class, but as we couldn't find out why it happened in the first place.
We wrote this example code to reproduce the problem (which resembles our original code), and hope someone is able to explain why it happens.
public partial class ClassRefTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var myclass = new MyClass();
var copy = myclass;
myclass.Mystring = "jadajadajada";
Dal.DoSomeThing(copy);
lit.Text = myclass.Mystring; //Text is expected to be jadajadajada,
but ends up to be referenced
}
}
public class MyClass
{
public string Mystring { get; set; }
}
public static class Dal
{
public static int? DoSomeThing(MyClass daclass)
{
daclass.Mystring = "referenced";
return null;
}
}
As you can see, in the DoSomething() method we're not using any ref argument, but still the lit.Text ends up to be referenced.
Why does this happen?
It is always interesting to explain how this works. Of course my explanation could not be on par with the magnificiency of the Jon Skeet one or Joseph Albahari, but I would try nevertheless.
In the old days of C programming, grasping the concept of pointers was fundamental to work with that language. So many years are passed and now we call them references but they are still ... glorified pointers and, if you understand how they work, you are half the way to become a programmer (just kidding)
What is a reference? In a very short answer I would tell. It is a number stored in a variable and this number represent an address in memory where your data lies.
Why we need references? Because it is very simple to handle a single number with which we could read the memory area of our data instead of having a whole object with all its fields moved along with our code.
So, what happens when we write
var myclass = new MyClass();
We all know that this is a call to the constructor of the class MyClass, but for the Framework it is also a request to provide a memory area where the values of the instance (property, fields and other internal housekeeping infos) live and exist in a specific point in time. Suppose that MyClass needs 100 bytes to store everything it needs. The framework search the computer memory in some way and let's suppose that it finds a place in memory identified by the address 4200. This value (4200) is the value that it is assigned to the var myclass It is a pointer to the memory (oops it is a reference to the object instance)
Now what happens when you call?
var copy = myclass;
Nothing particular. The copy variable gets the same value of myclass (4200). But the two variables are referencing the same memory area so using one or the other doesn't make any difference. The memory area (the instance of MyClass) is still located at our fictional memory address 4200.
myclass.Mystring = "jadajadajada";
This uses the reference value as a base value to find the area of memory occupied by the property and sets its value to the intern area where the literal strings are kept. If I could make an analogy with pointers it is as you take the base memory (4200), add an offset to find the point where the reference representing the propery MyString is kept inside the boundaries of the 100 bytes occupied by our object instance. Let's say that the MyString reference is 42 bytes past the beginning of the memory area. Adding 42 to 4200 yelds 4242 and this is the point in which the reference to the literal "jadajadajada" will be stored.
Dal.DoSomeThing(copy);
Here the problem (well the point where you have the problem). When you pass the copy variable don't think that the framework repeat the search for a memory area and copy everything from the original area in a new area. No, it would be practically impossible (think about if MyClass contains a property that is an instance of another class and so on... it could never stop.) So the value passed to the DoSomeThing method is again the reference value 4200. This value is automatically assigned to the local variable daclass declared as the input parameter for DoSomething (It is like you have explicitly done before with var copy = myclass;.
At this point it is clear that any operation using daClass acts on the same memory area occupied by the original instance and you see the results when code returns back to your starting point.
I beg the pardon from the more technically expert users here. Particularly for my casual and imprecise use of the term 'memory address'.
that's normal since your MyClass is a reference type so you are passing a reference to original data not the data itself this why it's an expected behavior
here is an explanation of what a reference type is from Parameter passing in C#
A reference type is a type which has as its value a reference to the appropriate data rather than the data itself
I see two issues here...
Making a Copy of an object
var copy = myClass; does not make a copy - what it really does is create a second reference ("pointer") to myClass (naming the variable "copy" is misleading). So you have myClass and copy pointing to the same exact object.
To make a copy you have to do something like:
var copy = new MyClass(myClass);
Notice that I created a new object.
Passing By Reference
When passing value type variables without ref, the variable cannot be changed by the the receiving method.
Example: DoSomething(int foo) - DoSomething cannot affect the value of foo outside of itself.
When passing value type variables with ref, the variable can be changed
Example: DoSomething(ref int foo) - if DoSomething changes foo, it will remain changed.
When passing an object without ref, the object's data can be changed, but the reference to the object cannot be changed.
void DoSomething(MyClass myClass)
{
myClass.myString = "ABC" // the string is set to ABC
myClass = new MyClass(); // has no affect - or may not even be allowed
}
When passing an object with ref, the object's data can be changed, and the reference to the object can be changed.
void DoSomething(ref MyClass myClass)
{
myClass.myString = "ABC" // the string is set to ABC
myClass = new MyClass(); // the string will now be "" since myClass has been changed
}
The docs at MSDN say it pretty clearly. Value types are passed as a copy by default, objects are passed as a reference by default. Methods in C#

C# - References passed by value

Quick question :
I am passing a class (reference type) to a method without using the "ref" keyword. Thus, the reference itself to my class is passed by value.
Then, I change the reference of my class (I make the reference point to another instance defined inside my method).
Finally, I return the initial method. However, in this case the returned instances points to the instance of the second class.
public Class Foo(Class A)
{
Class B = new Class();
A = B;
return A;
}
Foo returns a references pointing to B !
I am a little bit confused, since when doing A = B I make the reference of A point to another reference, or A's referenced is passed by value.
EDIT 1
Thanks for the response, but If I take the following example the change is not reflected. Indeed, I am trying to change the references of A but A's references is passed by value so in this case I understand why the change is not reflected..
void Foo(Class A)
{
A = null;
}
Many Thanks.
Basically, when you're passing an object, a reference is passed:
When an object of a reference type is passed to a method, a reference to the object is passed. That is, the method receives not the object itself but an argument that indicates the location of the object. If you change a member of the object by using this reference, the change is reflected in the argument in the calling method, even if you pass the object by value.
You can read more on this MSDN page.
You can read more on the other answers, but do notice that you're returning a class. Usually you'll return a specific object type, and when you won't be so free to do silly things like that. (of course, assuming that B inherits from A, you could create a new B inside the method and return it, which will be valid, but still, it's not making sense).
Another thing you might want to remember is the ref and out.
ref will expect an initialized value, and that value is changed in the method.
out doesn't care what it gets in, but you need to initialize and set it in the method.
Other than that, and the other answers here, either be more specific with your question and code, or have a read at the different links in the answers :)
You are passing a reference - an immutable value - into the method using the mutable variable, more precisely a parameter, A. Then you assign to the mutable variable A a new value, the immutable reference to the newly created object. Finally you are returning the current value of the variable A which at that point is the reference to the new object and no longer the reference to the object you passed into the method.
Essentially you are confusing the variable and the value stored in that variable. At no point did you change any reference, you only exchanged the value, i.e. reference, stored in the variable.
When you pass reference type by value the attempt to reassign the parameter to a different memory location only works inside the method and does not affect the original variable.
Check out Passing reference - type parameters .

Entity Framework: How does the data context deal with duplicate objects?

So today I discovered that c# passes reference types by value by default. This ran counter to what I thought I understood - reference types are by reference as standard. Oh well.
This led me to think about a method that I had that took an entity object as a parameter, attached to a context, and made some changes to it. The method did not return the object. When calling save changes on my context, the changes made within the method were applied.
I assumed at the time that it worked because I was passing a reference to the object and so could happily alter it without having to return anything to reassign.
So the question is, how does this work? (the code did work as I expected).
Thanks,
Yes, this stuff is tricky. I've found myself not thinking about it for a few months, and then having to think about it for a few seconds to get it straight in my head again. Even though I've understood it for a long time.
Even though the parameter is by value, that just means that a new reference variable is created, but still pointing to the same object. If you make the parameter by reference, then the same pointer would be passed in, which of course points to the same object.
It makes a difference when you mess with the parameter variable. If you set it to null or to some other object, the variable "outside" will not be affected. But if the parameter was passed in by value, then setting the variable to null or another object will alter the reference "outside".
For a value type, whether the parameter is by reference or by value makes a practical difference more often. Changes to the value or to a member (if it's a struct) will not be reflected "outside" if passed by value.
Here's a good explanation with easy examples.
The reference is passed by value (ie the reference is copied not the target object) - it is still a reference to the same object. This is as opposed to passing by reference, where the original reference is passed around.
Hopefully this illustrates the point:
var myObject = new object();
PassByValue(myObject);
Console.WriteLine(myObject == null); // returns false. The fact the method changed its *copy* of the reference to null doesn't affect the caller.
PassByReference(ref myObject);
Console.WriteLine(myObject == null); // returns true. We actually passed in our reference itself, not a copy of the reference; so when the method set it to null, it nulled the reference we held in the caller.
void PassByValue(object obj)
{
obj = null;
}
void PassByReference(ref object obj)
{
obj = null;
}
Reference types in C# are passed by reference. Which means when you pass a reference type only reference is passed to that method not the actual value
When you pass a reference type object to a method you are actually passing a new reference/pointer to that object
Let's understand by example
SomeRefType myRef = new SomRefType();
//above myRef is reference to object of SomRefType type
//pass this reference to a method
SomeMethod(myRef);
SomeMethod(SomeRefType reference)
{
//here reference is a new pointer/reference pointing to same object as myRef
}

Categories