Problem
Non-primitive variables were always passed by reference in C#, whereas primitive values were always provided by value.
So, if you provide a non-primitive object to a method, anything done to the object in the method will affect the object you’re passing. (Stuff from C# 101)
However, I’ve found that this does not appear to be the case when I pass a System.Drawing.Image object? That picture is not loaded on the original object if I send a system.drawing.image object to another function and load an image onto that object, then let that method go out of scope and return to the calling method?
Why is this?
Asked by michael
Solution #1
Objects aren’t even passed. The argument is evaluated by default, and its value is supplied as the initial value of the parameter of the method you’re calling, by value. The crucial thing to remember now is that the value is a reference for reference types – a method to access an object (or null). The caller will be able to see any changes made to that item. When you use pass by value, which is the default for all kinds, changing the value of the parameter to refer to a different object will not be visible.
Whether the parameter type is a value type or a reference type, you must use out or ref if you want to use pass-by-reference. The variable is effectively passed by reference in this situation, because the parameter utilizes the same storage location as the argument – and changes to the parameter are visible to the caller.
So:
public void Foo(Image image)
{
// This change won't be seen by the caller: it's changing the value
// of the parameter.
image = Image.FromStream(...);
}
public void Foo(ref Image image)
{
// This change *will* be seen by the caller: it's changing the value
// of the parameter, but we're using pass by reference
image = Image.FromStream(...);
}
public void Foo(Image image)
{
// This change *will* be seen by the caller: it's changing the data
// within the object that the parameter value refers to.
image.RotateFlip(...);
}
I have an article which goes into a lot more detail in this. Basically, “pass by reference” doesn’t mean what you think it means.
Answered by Jon Skeet
Solution #2
There had been a slew of excellent responses added. I still want to participate; perhaps it will help to clarify things a little further.
When you send an instance to a method as an argument, it returns a copy of the instance. If the instance you pass is a value type (one that lives on the stack), you’ll get a copy of it, so any changes you make won’t be reflected in the caller. If the instance is a reference type, you provide the object a copy of the reference (which is stored in the stack again). So you got two references to the same object. Both of them can modify the object. But if within the method body, you instantiate new object your copy of the reference will no longer refer to the original object, it will refer to the new object you just created. So you will end up
Answered by OlegI
Solution #3
To demonstrate this, here’s another code example:
void Main()
{
int k = 0;
TestPlain(k);
Console.WriteLine("TestPlain:" + k);
TestRef(ref k);
Console.WriteLine("TestRef:" + k);
string t = "test";
TestObjPlain(t);
Console.WriteLine("TestObjPlain:" +t);
TestObjRef(ref t);
Console.WriteLine("TestObjRef:" + t);
}
public static void TestPlain(int i)
{
i = 5;
}
public static void TestRef(ref int i)
{
i = 5;
}
public static void TestObjPlain(string s)
{
s = "TestObjPlain";
}
public static void TestObjRef(ref string s)
{
s = "TestObjRef";
}
And the output:
Answered by vmg
Solution #4
I suppose it’s easier to understand when you do it this way. To test things like this, I recommend downloading LinqPad.
void Main()
{
var Person = new Person(){FirstName = "Egli", LastName = "Becerra"};
//Will update egli
WontUpdate(Person);
Console.WriteLine("WontUpdate");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
UpdateImplicitly(Person);
Console.WriteLine("UpdateImplicitly");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
UpdateExplicitly(ref Person);
Console.WriteLine("UpdateExplicitly");
Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
}
//Class to test
public class Person{
public string FirstName {get; set;}
public string LastName {get; set;}
public string printName(){
return $"First name: {FirstName} Last name:{LastName}";
}
}
public static void WontUpdate(Person p)
{
//New instance does jack...
var newP = new Person(){FirstName = p.FirstName, LastName = p.LastName};
newP.FirstName = "Favio";
newP.LastName = "Becerra";
}
public static void UpdateImplicitly(Person p)
{
//Passing by reference implicitly
p.FirstName = "Favio";
p.LastName = "Becerra";
}
public static void UpdateExplicitly(ref Person p)
{
//Again passing by reference explicitly (reduntant)
p.FirstName = "Favio";
p.LastName = "Becerra";
}
And this should result in
WontUpdate
Egli, Egli, Egli, Egli, Egli, Egli, Egli, Egli, Egli, Egli, E
UpdateImplicitly
Favio, Favio, Favio, Favio, Favio, Favio, Favio, Favio, F
UpdateExplicitly
Favio, Favio, Favio, Favio, Favio, Favio, Favio, Favio, F
Answered by Egli Becerra
Solution #5
When you have completed the System. Drawing. When you give an image type object to a method, you’re actually passing a copy of the object’s reference.
So, if you’re loading a new image in that technique, you’re doing so with a new/copied reference. You are not altering the original.
YourMethod(System.Drawing.Image image)
{
//now this image is a new reference
//if you load a new image
image = new Image()..
//you are not changing the original reference you are just changing the copy of original reference
}
Answered by Haris Hasan
Post is based on https://stackoverflow.com/questions/8708632/passing-objects-by-reference-or-value-in-c-sharp