Greetings,
I get the difference between pass by value and pass by reference. But pass reference (such as array) by ref and pass array by value is something i can't seem to comprehend. How can you pass a reference by reference?
int[] myArray = {1,2,3};
PassByVal(myArray);
PassByRef(ref myArray);
PassByVal(int[] array)
{ array = new int[] {7,8,9}; // will not work }
PassByRef(ref int[] array)
{ array = new int[] {10,11,12}; } // will work
If you pass a reference by reference you can make the variable passed in point to a new object. If you pass the reference by value you still can change the state of the object, but you can't make the variable point to a different object.
Example:
void RefByRef(ref object x)
{
x=new object(2);
}
void RefByValue(object x)
{
x=new object(2);//Only changes a local variable and gets discarded once the function exits
}
void Test()
{
object x1=1;
object x1a=x1;
RefByRef(ref x1);
//x1 is now a boxed 2
//x1a is still a boxed 1
object x2=1;
RefByValue(x2);
//x2 is still a boxed 1
}
I suggest that you check out this link. It's quite useful and contains very simple examples about Parameter passing in C#.
Reference parameters don't pass the values of the variables used in the function member invocation - they use the variables themselves. Rather than creating a new storage location for the variable in the function member declaration, the same storage location is used, so the value of the variable in the function member and the value of the reference parameter will always be the same. Reference parameters need the ref modifier as part of both the declaration and the invocation - that means it's always clear when you're passing something by reference. Let's look at our previous examples, just changing the parameter to be a reference parameter:
void Foo (ref StringBuilder x) {
x = null;
}
...
StringBuilder y = new StringBuilder();
y.Append ("hello");
Foo (ref y);
Console.WriteLine (y==null); // will write TRUE
IN YOUR EXAMPLE
int[] myArray = {1,2,3};
PassByVal(myArray);
PassByRef(ref myArray);
PassByVal(int[] array){
// the function copy the value of the pointer in a new location of memory
// the "copied" pointer still points to the array 123
// now you are modifying the object pointed by THE COPY of the pointer
// the original pointer still points to array 123
// the copy of the pointer will point to array 456
array = new int[] {7,8,9};
} // will not work
PassByRef(ref int[] array){
// here you are passing the pointer without creating a copy of it in a
// new location of memory
// we have not a original pointer and a "copyed" pointer
// we have only the original pointer and now whe point it to array 10,11,12
array = new int[] {10,11,12};
} // will work
In order to answer your question let's first look at ValueTypes
A ValueType holds the Value. That is it does not in turn point to another memory location that holds the value but rather it's memory location is the value.
so
int i = 10;
int j = i;
What happens here is that a copy of the value of i is assigned to j. They both have the same value but they are different locations in memory. In oter words, each time you assign a valuetype to another valuetype, a copy is made.
Contract this with ReferenceTypes.
object o = 10;
object p = o;
because o is a ReferenceType o points to a memory location that holds the value of 10 (it is really boxed but I'll keep it simple). In the next line p now points to the same memory location. In other words, reference tyes have two things going.
1. An address pointer
2. The actual memory location (that address points to) that holds the actual "thing".
If you get it do far, then we can move on the passing by value and by reference.
In C# parameters are passed by value. So if you're passing a valueType to a method that expects a valuetype parameter, then
int i = 10;
SomeMethod(i);
Console.WriteLine(i);
static void SomeMethod(int value)
{
value = 20;
}
When the call is made to SomeMethod a copy of the value of i is sent to the method. If the method manipulates the parameter, it does not affect the original variable i. So what you'll see in the console window is 10;
contract this with reference types;
class Program
{
static void Main(string[] args)
{
Customer c = new Customer() { Name = "Mike" };
SomeMethod(c);
Console.WriteLine(c.Name);
}
static void SomeMethod(Customer customer)
{
customer.Name = "John";
}
}
class Customer
{
public string Name { get; set; }
}
Since c is a reference type. And C# passes parameters by value. a copy of the "value" of the reference is passed. That is the value of the Address c is pointing to is passed. In the method, since the address is the same (it's a copy but it points to the same memory location), the method is able to manipulate the state of object. So what you'll see in the console window is "John" and not "Mike".
However, if the method attempts to assign another instance to the parameter (called "customer" in this case). then things change.
class Program
{
static void Main(string[] args)
{
Customer c = new Customer() { Name = "Mike" };
SomeMethod(c);
Console.WriteLine(c.Name);
}
static void SomeMethod(Customer customer)
{
customer = new Customer();
customer.Name = "John";
}
}
class Customer
{
public string Name { get; set; }
}
Notice that in the method we create a new instance of a Customer and assign it to the parameter customer and we set the name of this new instance to "John". What we'll see in the console window is "Mike" and not john.
That is because a copy of the original variable (c) was made before passing it to the method. While now in the method we have another address and then manipulate that new address so the original instance is untouched. Make sense?
Ok, if that makes sense. then what if we actually wanted the SomeMethod to be able to do what we attempted to do? Well, then the parameter can't be passed by value but it has to be passed by reference. Meaning that the variable c and the two part (the value of address it is pointing and the address itself) are being passed. So now you're passing a reference type by reference.
class Program
{
static void Main(string[] args)
{
Customer c = new Customer() { Name = "Mike" };
SomeMethod(ref c);
Console.WriteLine(c.Name);
}
static void SomeMethod(ref Customer customer)
{
customer = new Customer();
customer.Name = "John";
}
}
class Customer
{
public string Name { get; set; }
}
This may seem a bit confusing, but it's really not that tricky. When you assign an instance of a reference type to a variable, you could say the value of that variable will be a reference to the object, not the object itself. When you pass that variable by value to another method, you are passing a copy of the reference. The called method will "see" the same instance as the calling code does. If you instead pass the variable by reference, the calling method gets to see the same copy of the reference as the calling code does.
The difference in behavior between these to is that when you pass the variable by reference, the called method might assign another reference to the variable (make it reference another instance of the same type), and the calling code will see this change. Unless you make such assignments, there is no need to use ref.
Related
I am a bit confused here. With structs, I cannot directly change its fields as the whole struct is of the value type.
But what about classes with value type fields? If I have a public field int X, I can modify it properly. So the only manifestation of value-type nature of its field would be that when passed as an argument, it is a copy?
EDIT: Also
Class A
{
int B=100; //this is a field, so reference type. But it is a value type.
}
The address to content of B is stored on the heap, but is the value of B stored on the stack?
With structs, I cannot directly change its fields as the whole struct is of the value type.
You cannot change fields in situations when C# makes a copy of the struct for you. In other situations, you can modify fields of a struct. Here is a small demonstration of the difference:
struct Foo {
public int A {get;set;}
public void SetA(int a) {
A = a;
}
}
class Bar {
Foo f;
public Foo F {
get{return f;}
set {f = value;}
}
public void SetFooA(int x) {
f.SetA(x);
}
}
public static void Main() {
Bar b = new Bar();
b.F.SetA(123); // b.F makes a copy, so changing A fails
Console.WriteLine("{0}", b.F.A);
b.SetFooA(456); // Inside Bar, f.SetA is called directly, so the change works fine
Console.WriteLine("{0}", b.F.A);
b.F = new Foo { A = 112233 }; // This also works, because the whole F is assigned
Console.WriteLine("{0}", b.F.A);
}
If I have a public field int X, I can modify it properly.
The same rule applies to user-defined structs, as long as you modify the whole of it. You can't modify part of an int, because it is not a composite. Modification of a struct works fine when you assign the whole struct at once. In other words, assigning
b.F = new Foo { A = 112233 };
in my example replaces assigning
B = 100;
in your example.
Demo.
The address to content of B is stored on the heap, but is the value of B stored on the stack?
No. Value type fields of a class are stored on the heap.
Please refer to #Marc Gravell's answer here for more information about this:
Why value-types are stored onto Stacks?
You may also want to read #Eric Lippert's blog post on the subject: https://blogs.msdn.microsoft.com/ericlippert/2010/09/30/the-truth-about-value-types/
In short value types can be stored on the stack but they are not always stored on the stack.
Struct gives you a copy of the original field because a copy of the struct would be passed. Changing it to class would pass a reference to the class and therefore the field would modify if you were to change it.
I don't understand one thing about passing parameters to methods in c#. From what I see objects in c# sometimes behave like the have been passed by reference and once as if they were passed by value. In this code I pass to method() one by reference and once by value. Both of these execute as expected. But when I created Update() and pass an object by value I see it behaving like it is updating original object.
Why do I update original object with Update(myString input) but do not update it with method(myString input)?
This is illogical!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ClassPassing
{
class Program
{
static void Main(string[] args)
{
myString zmienna = new myString();
Update(zmienna);
Console.WriteLine(zmienna.stringValue);
Console.WriteLine(zmienna.stringValue2);
Console.ReadLine();
zmienna.stringValue = "This has run in main";
zmienna.stringValue2 = "This is a help string";
method(zmienna);
Console.WriteLine(zmienna.stringValue);
Console.WriteLine(zmienna.stringValue2);
Console.ReadLine();
method(ref zmienna);
Console.WriteLine(zmienna.stringValue);
Console.WriteLine(zmienna.stringValue2);
Console.ReadLine();
}
static void method(myString input)
{
input = new myString();
}
static void method(ref myString input)
{
input = new myString();
}
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
}
public class myString
{
public string stringValue { get; set; }
public string stringValue2 { get; set; }
public myString() { stringValue = "This has been just constructed"; this.stringValue2 = "This has been just constructed"; }
}
}`
You have to understand your code:
static void method(myString input)
{
input = new myString();
}
Here you pass reference to object by value
static void method(ref myString input)
{
input = new myString();
}
Here you pass reference to object by reference
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
Here again you pass reference to object by value
Now:
When you pass object reference by value, you can change the contents of the object, but you cannot change the reference itself (assign it to another object).
When you pass object reference by reference, you can both change the contents of the object and you can modify the reference itself (assign it to another object).
The real passing by value in C# occurs only in case of simple (int, float, etc.) types and in case of structs:
class Program
{
public struct MyStruct
{
public int i;
}
public class MyClass
{
public int i;
}
public static void Modify(MyStruct s)
{
s.i = 99;
}
public static void Modify(MyClass c)
{
c.i = 99;
}
public static void Main(string[] args)
{
MyStruct myStruct = new MyStruct();
myStruct.i = 20;
MyClass myClass = new MyClass();
myClass.i = 20;
Modify(myStruct);
Modify(myClass);
Console.WriteLine("MyStruct.i = {0}", myStruct.i);
Console.WriteLine("MyClass.i = {0}", myClass.i);
Console.ReadKey();
}
}
Result:
MyStruct.i = 20
MyClass.i = 99
In this case, MyStruct's value remained unchanged, because it was passed to a function by value. On the other hand, MyClass's instance was passed by reference and that's why its value changed.
Objects aren't passed at all.
For expressions of a reference type (classes, interfaces etc) references are passed - by value by default, but the variables are passed by reference if you use ref.
It's important to understand that the value of zmienna isn't an object - it's a reference. Once you've got that sorted, the rest becomes simple. It's not just for parameter passing either - it's for everything. For example:
StringBuilder x = new StringBuilder();
StringBuilder y = x;
y.Append("Foo");
Console.WriteLine(x); // Prints Foo
Here the values of x and y are references to the same object - it's like having two pieces of paper, each of which has the same street address on. So if someone visits the house by reading the address written on x and paints the front door red, then someone else visits the same house by reading the address written on y, that second person will see a red front door too.
See my articles on reference and value types and parameter passing for more details.
There may be multiple questions to answer here, but regarding your last one:
"Why do I update original object with Update(myString input) but do not update it with method(myString input)?"
Here, you are creating a new instance of the myString class and not referencing the original that was passed to the method as a parameter. So if you change the value of input.stringValue2 inside the method, you will lose the value once you leave the method.
static void method(myString input)
{
input = new myString();
}
But here you are referencing the original instance passed to it. When you leave this method, the original myString instance will retain the value of stringValue2.
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
Imagine computer memory as a set of boxes, and that you can give them names using labels.
myString zmienna = new myString();
Here you allocate a box with an instance of myString in it, and have a label zmienna pointing to it. Then:
static void method(myString input)
{
input = new myString();
}
In this method, input is an another label. Calling the method you first make the label input point to the same box, with the initial instance. However in the method's body you allocate another box, and change the label input to point to that new box. Nothing is being done with the first box, and nothing is being done with zmienna label.
static void method(ref myString input)
{
input = new myString();
}
Here, because of the ref keyword you're not only passing the whereabouts of the first "memory box", but you give the actual label. So this method's body updates your label zmienna to point to a newly created box, with a second instance of myString. The first box is being forgotten, as no labels point to it.
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
In this case, you pass the address of the first box, in exactly the same manner as in the first method. So you have two labes: zmienna and input - both pointing to the same box. Therefore input.stringValue2 accesses the field stringValue2 in the same box that is pointed by zmienna.
A precise term actually used is reference instead of label term I'm using in this explanation. I somehow find that many people find it easier to comprehend this way :)
The application is printing 24 but shouldn't it be printing 18 when we know that without ref keyword only a copy of object is passed and no change is made to the original object.
I have created a class called myclass and an object me. age is a public variable in class myclass.
I have set me.age as 18 and through the method show I have changed it to 24.
class Program
{
static void Main(string[] args)
{
myclass me = new myclass();
me.age = 18;
show(me);
Console.WriteLine(me.age);
Console.ReadLine();
}
public static void show( myclass you)
{
you.age = 24;
}
}
class myclass
{
public int age;
}
Don't confuse the variable and what the variable points to.
When you have:
MyClass myVar = new MyClass();
MyClass myVar2 = myVar;
That will create only a single instance of an object, but 2 variables pointing to it.
The same thing is happening to your parameter: you is a copy of the variable me, but both point to the same object. So when you modify you.age, you are also modifying me.age.
In your function, if you then did
you = new myClass();
only then would me and you refer to different objects. If you did this, me would still point to the original object.
If you added ref to the parameter you, then if you did
you = new myClass();
then the variable me would be updated to point to that same object.
For objects, you need to separate the variable from what the variable points to.
It's printing the right thing.
myclass is an object, and the default behavior is to pass the reference of the object in C#, so when you don't specify anything, you pass the reference.
If you declare struct myclass though, you'll have the behavior you want, because structs aren't references by default.
You're probably confusing this with C++ classes. In C#, classes are reference types, which means that whenever you have a variable of a type that's class, that variable doesn't hold the object itself, it holds only a reference to it (you can think of it as a pointer). So, when you pass your object into a method, you actually pass a reference to that object. This means the behavior you're observing is correct.
C# also supports value types (unlike e.g. Java), which you create by using struct instead of class. If you changed myclass into a srtuct, you would get the behavior you expected.
You are confusing value types and reference types.
public void addTwo(int a)
{
a += 2;
}
...
int a = 5;
addTwo(a);
Console.WriteLine(a); // will give "5";
public void addTwo(ref int a)
{
a += 2;
}
...
int a = 5;
addTwo(ref a);
Console.WriteLine(a); // will give "7";
For reference types (anything that is defined as class instead of struct, what you are passing on is a reference to the object, not a copy. So you are in fact changing the object.
You are sending an object to your function.
Not an atomic type or a struct, therefor it is sent by reference (this is how C# works), anything you change in this object in the function will also change in the original object because it is the same.
More information about passing parameters: http://msdn.microsoft.com/en-us/library/0f66670z(v=vs.71).aspx
As far as I know Class and Object are reference type.
I have below method to Change the Value
public void ChangeValue(MyClass classobj)
{
classobj.Number = classobj.Number*2;
}
I invoke the method to double the value
var myClass=new MyClass();
int myNumber = 10;
myClass.Number = myNumber;
ChangeValue(myClass);
And it will be return 20 which is fine as you can interpret it as when you make object of your class then it pass reference to method and it will update the reference values.
but my question is why its not happening for Object type. In other words why when I make object and assign some value to it like below
object myObject = new object();
string sometext = "Some object value";
myObject = sometext;
ChangeValue(myObject)
it wont change the value after executing the method
public void ChangeValue(object objectValue)
{
objectValue = null;
}
I know the parameter of methods are value types but can not understand it have different behavior for two reference type.
You're actually doing two different things here. Object and your MyClass are indeed both reference types, which means you pass a reference to the actual object into the ChangeValue method. However, the reference that you see inside the method is a copy of the reference the caller holds. They point to the same object, so when you manipulate the object in the method the caller of the method can see your changes, but changes to the actual reference inside the method only affect the method itself.
In an attempt to summarise, objects are passed by reference, but those references are passed by value.
In your method
public void ChangeValue(object objectValue)
{
objectValue = null;
}
What you're actually doing is reassigning the reference objectValue, and that reference is a copy of the reference called myObject which the caller has. Because the method only has a copy, it can't affect the caller's reference at all.
There is a way to make this work, you have to pass the reference by reference. Which always gives me a headache, but that's what the ref keyword is for.
public void ChangeValue(ref object objectValue)
{
objectValue = null; // this is the SAME reference as the caller has, so the caller will see this change
}
However then it also has to be called that way:
ChangeValue(ref myObject);
so that it's obvious at the call site that it might come back pointing to a different object. It's important to know that, as you might still have things relying on the old value and end up in a horrible confused mess if references were pointing to different objects unexpectedly.
You pass the objectValue to the ChangeValue(object objectValue) by value and this value is a reference. Then you change this value, but not the value of the myObject.
You have to pass it as ChangeValue(ref object objectValue) to actually pass the value of reference by reference.
It's not a different behavior, you're doing different things
This will work exactly as your object example:
public void ChangeValue(MyClass classobj)
{
classobj = null;
}
And this will work as your first example(assuming you will pass MyClass instance):
public void ChangeValue(object objectValue)
{
((MyClass)objectValue).Number *= 2;
}
What realy happens here is that when you are assigning parameter (not a property or field of parameter) you are only changing that parameter's value. Original value and variable in calling code stay intact.
The same happens here:
MyClass a = new MyClass();
MyClass b = a;
a = null;
// b still contains the value created in the first line
Simply speaking, reference variables hold the pointer (memory address) of the actual value.
By changing variable's value, you are making it point to different object or null.
But when you are doing a.field=2 this means you are taking the object a is referencing to and changing it's field member value.
I've created a class that takes in an object as a parameter by ref. When it takes this object in it's construct it is null. Why does it stay null (uninitialized)?
// example code, not real
class Test{
object parent;
public Test (ref object _parent)
{
parent = _parent;
}
}
object n = null;
Test t = new Test (ref n);
n = new Something ();
When I tried it with a different class (http://pastebin.com/PpbKEufr), it stayed null
Yes, parent will stay null regardless of what you eventually assign to the variable n. The ref keyword will pass the actual reference to n (as opposed to a copy of it) into your method, and is typically used if your method was intended to assign a new object instance to the parameter.
Inside your method, you are making a copy of the reference that n points to, in this case null. When the method completes both n and parent point to null. When later you assign to n, you haven't changed the object to which n and parent point, rather you have asked n to point to a new location, leaving parent still pointing to null.
If you were to create an instance of an object and assign it to n, then parent would point to the same object and any changes to that object's properties would be visible to your class. The same would be true if you did not pass the parameter as ref, as the reference copy also would point to the same object instance.
Hope that helps.
It is not possible to change a private member of a class that way as this would break the idea of encapsulation.
In order to change (i.e. replace) an object stored in a private field you must do so explicitly via a public property or method of that class, e.g.
class Test
{
object parent;
public Test (ref object _parent)
{
parent = _parent;
}
public object Parent
{
get { return parent; }
set { parent = value; }
}
}
object n = null;
Test t = new Test (ref n);
n = new Something ();
t.Parent = n;
This way the language makes sure that data of an object cannot (accidentally) be changed from the outside, which might lead to the strangest effects.
The ref arguments in C# refer to the instance "pointed" by the argument.
For example, if you'd change _parent in the constructor and store it in other instance, then n would change too.
In the posted code you're copying the referenced instance (null) into parent. Meaning, it copies the referenced instance into the field and not the reference of the argument itself.
For example, method that changes the ref argument:
public void M(ref object arg)
{
arg = new object();
}
And a usage example:
[Test]
public void SetReferenceArgument()
{
var myClass = new MyClass();
object arg = null;
myClass.M(ref arg);
Assert.That(arg, Is.Not.Null);
}
ref argument lets us assign an instance into the argument which will change the reference both in the of the method and in the context of the caller.