I have something interesting that I want to understand little deeper.
I have an extension class that extends int:
public static class MyExtension
{
public static void GetProp(this int i, MyObject o)
{
var val = i;
o.sum = i;
}
}
That uses a class as one of its parameter:
public class MyObject
{
public int sum { get; set; }
}
Now, lets see the unit test class:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void test()
{
int a = 1;
int b = 2;
int sum = 0;
Add(a, b, sum);
//Here, sum=3 but after its execution, sum looses its value and
retains the value sum = 0
int test = 4;
MyObject obj = new MyObject();
test.GetProp(obj);
But in the above code when I pass the variable using the extension
method, the obj.sum retains its value obj.sum = 4 . I am not passing any
value by reference. The first portion of code seems to follow the
passing ByVal. But the second portion of extension method, the value
is retained as if its passed as ByRef
string s = sum.ToString();
string p = obj.sum.ToString();
}
private void Add(int x, int y, int sum)
{
sum = x + y;
}
}
Can someone explain the mechanism behind this. Thanks
All parameters are send by value, unless you specify them with the ref or out keyword. Passing a parameter by value means that the value is copied.
However, when you pass an object by value it's not the object that is copied, it's the reference that is copied. That means that you have two references to the same object, one in the obj variable and one in the o parameter, but only one object.
When the extension method accessed the object, it's the same object as outside the method. Any change to the property made using the o parameter will be visible when you later access it using the obj variable.
This is the difference between passing by reference and passing a reference object (class). In GetProp, you aren't modifying the reference obj, you are modifying the MyObject instance that is referred by obj.
If I understand your question, you're confused about why the sum variable isn't changed when it is passed by value, but the obj.sum property does retain its value when obj is passed by reference. The other answers do a good job of explaining this.
In your question, you pass a parameter by value as a receiver, and this confuses your question a bit. Your question appears to be, "why is it that when I pass normally, it's treated as by-value, but when I pass as a receiver to an extension method, it's by-reference?"
Ah. Try assigning a new value to the receiver and see what happens at the call site:
public static void GetProp(this int i, MyObject o)
{
o.sum = i;
i = 5000;
}
You'll find that the variable test at the call site is not affected by this, since the receiver is also passed by value!
Related
In C#, I have always thought that non-primitive variables were passed by reference and primitive values passed by value.
So when passing to a method any non-primitive object, anything done to the object in the method would effect the object being passed. (C# 101 stuff)
However, I have noticed that when I pass a System.Drawing.Image object, that this does not seem to be the case? If I pass a system.drawing.image object to another method, and load an image onto that object, then let that method go out of scope and go back to the calling method, that image is not loaded on the original object?
Why is this?
Objects aren't passed at all. By default, the argument is evaluated and its value is passed, by value, as the initial value of the parameter of the method you're calling. Now the important point is that the value is a reference for reference types - a way of getting to an object (or null). Changes to that object will be visible from the caller. However, changing the value of the parameter to refer to a different object will not be visible when you're using pass by value, which is the default for all types.
If you want to use pass-by-reference, you must use out or ref, whether the parameter type is a value type or a reference type. In that case, effectively the variable itself is passed by reference, so the parameter uses the same storage location as the argument - and changes to the parameter itself are seen by 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.
Lots of good answers had been added. I still want to contribute, might be it will clarify slightly more.
When you pass an instance as an argument to the method it passes the copy of the instance. Now, if the instance you pass is a value type(resides in the stack) you pass the copy of that value, so if you modify it, it won't be reflected in the caller. If the instance is a reference type you pass the copy of the reference(again resides in the stack) to the object. 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 having 2 references and 2 objects.
One more code sample to showcase this:
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:
TestPlain:0
TestRef:5
TestObjPlain:test
TestObjRef:TestObjRef
I guess its clearer when you do it like this. I recommend downloading LinqPad to test things like this.
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 that should output
WontUpdate
First name: Egli, Last name: Becerra
UpdateImplicitly
First name: Favio, Last name: Becerra
UpdateExplicitly
First name: Favio, Last name: Becerra
When you pass the the System.Drawing.Image type object to a method you are actually passing a copy of reference to that object.
So if inside that method you are loading a new image you are loading using new/copied reference. You are not making change in 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
}
How did you pass object to method?
Are you doing new inside that method for object? If so, you have to use ref in method.
Following link give you better idea.
http://dotnetstep.blogspot.com/2008/09/passing-reference-type-byval-or-byref.html
Employee e = new Employee();
e.Name = "Mayur";
//Passes the reference as value. Parameters passed by value(default).
e.ReferenceParameter(e);
Console.WriteLine(e.Name); // It will print "Shiv"
class Employee {
public string Name { get; set; }
public void ReferenceParameter(Employee emp) {
//Original reference value updated.
emp.Name = "Shiv";
// New reference created so emp object at calling method will not be updated for below changes.
emp = new Employee();
emp.Name = "Max";
}
}
In Pass By Reference You only add "ref" in the function parameters and one
more thing you should be declaring function "static" because of main is static(#public void main(String[] args))!
namespace preparation
{
public class Program
{
public static void swap(ref int lhs,ref int rhs)
{
int temp = lhs;
lhs = rhs;
rhs = temp;
}
static void Main(string[] args)
{
int a = 10;
int b = 80;
Console.WriteLine("a is before sort " + a);
Console.WriteLine("b is before sort " + b);
swap(ref a, ref b);
Console.WriteLine("");
Console.WriteLine("a is after sort " + a);
Console.WriteLine("b is after sort " + b);
}
}
}
In the latest version of C#, which is C# 9 at this time of writing, objects are by default passed by ref. So any changes made to the object in the calling function will persist in the object in the called function.
In C#, I have always thought that non-primitive variables were passed by reference and primitive values passed by value.
So when passing to a method any non-primitive object, anything done to the object in the method would effect the object being passed. (C# 101 stuff)
However, I have noticed that when I pass a System.Drawing.Image object, that this does not seem to be the case? If I pass a system.drawing.image object to another method, and load an image onto that object, then let that method go out of scope and go back to the calling method, that image is not loaded on the original object?
Why is this?
Objects aren't passed at all. By default, the argument is evaluated and its value is passed, by value, as the initial value of the parameter of the method you're calling. Now the important point is that the value is a reference for reference types - a way of getting to an object (or null). Changes to that object will be visible from the caller. However, changing the value of the parameter to refer to a different object will not be visible when you're using pass by value, which is the default for all types.
If you want to use pass-by-reference, you must use out or ref, whether the parameter type is a value type or a reference type. In that case, effectively the variable itself is passed by reference, so the parameter uses the same storage location as the argument - and changes to the parameter itself are seen by 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.
Lots of good answers had been added. I still want to contribute, might be it will clarify slightly more.
When you pass an instance as an argument to the method it passes the copy of the instance. Now, if the instance you pass is a value type(resides in the stack) you pass the copy of that value, so if you modify it, it won't be reflected in the caller. If the instance is a reference type you pass the copy of the reference(again resides in the stack) to the object. 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 having 2 references and 2 objects.
One more code sample to showcase this:
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:
TestPlain:0
TestRef:5
TestObjPlain:test
TestObjRef:TestObjRef
I guess its clearer when you do it like this. I recommend downloading LinqPad to test things like this.
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 that should output
WontUpdate
First name: Egli, Last name: Becerra
UpdateImplicitly
First name: Favio, Last name: Becerra
UpdateExplicitly
First name: Favio, Last name: Becerra
When you pass the the System.Drawing.Image type object to a method you are actually passing a copy of reference to that object.
So if inside that method you are loading a new image you are loading using new/copied reference. You are not making change in 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
}
How did you pass object to method?
Are you doing new inside that method for object? If so, you have to use ref in method.
Following link give you better idea.
http://dotnetstep.blogspot.com/2008/09/passing-reference-type-byval-or-byref.html
Employee e = new Employee();
e.Name = "Mayur";
//Passes the reference as value. Parameters passed by value(default).
e.ReferenceParameter(e);
Console.WriteLine(e.Name); // It will print "Shiv"
class Employee {
public string Name { get; set; }
public void ReferenceParameter(Employee emp) {
//Original reference value updated.
emp.Name = "Shiv";
// New reference created so emp object at calling method will not be updated for below changes.
emp = new Employee();
emp.Name = "Max";
}
}
In Pass By Reference You only add "ref" in the function parameters and one
more thing you should be declaring function "static" because of main is static(#public void main(String[] args))!
namespace preparation
{
public class Program
{
public static void swap(ref int lhs,ref int rhs)
{
int temp = lhs;
lhs = rhs;
rhs = temp;
}
static void Main(string[] args)
{
int a = 10;
int b = 80;
Console.WriteLine("a is before sort " + a);
Console.WriteLine("b is before sort " + b);
swap(ref a, ref b);
Console.WriteLine("");
Console.WriteLine("a is after sort " + a);
Console.WriteLine("b is after sort " + b);
}
}
}
In the latest version of C#, which is C# 9 at this time of writing, objects are by default passed by ref. So any changes made to the object in the calling function will persist in the object in the called function.
Thank you. suppose I have two scripts.
I get a return value from a method in one script.
public class ClassA {
public int A (int a, int b)
{
return a + b;
}
}
and I want to use the returned value (int A) in another script:
class ClassB {
public ClassA _ClassA = new ClassA();
public int TheReturn;
public void update()
{
TheReturn = _ClassA.A;
}
}
That's how I tried it. And it is not working..
Thank you guys so much for pointing out the lack of argument in TheReturn = _ClassA.A;
If the Input for A is a reading value (a constantly changing value. eg SerialPort.Reading(), instead of int a, int b). And I want to use the actual "return" value from method A of ClassA. What should I do?
Can I use something like print() and then use Read() in another class?
your question is really messi, but maybe this is what you're looking for?
class ClassB
{
public ClassA _ClassA = new ClassA();
public int TheReturn;
public void update(int x, int y)
{
TheReturn = _ClassA.A(x,y);
}
}
Do not think in terms of scripts. For C# it does not matter whether the code is in one file or split among 100 files. This is only an organizational concern.
You have two classes.
ClassA declares a method A with two input parameters and one return value.
If you want to use this method, you first need to create to ClassA object. You are doing so. So far so good.
Then you must call this method and pass the required arguments.
ClassA aObject = new ClassA();
int result;
result = aObject.A(2, 7);
You do so by placing a pair of parentheses after the method name and around the argument list. In this example, the value returned by the method A is stored in the variable result. You could now print it like this
Console.WriteLine(result);
You can also use the result directly instead
Console.WriteLine(aObject.A(2, 7));
in fact, the method call can be part of an expression like
Console.WriteLine(aObject.A(2, 7) * aObject.A(3, 9) + 10);
See: Methods (C# Programming Guide)
I am trying to understand how to assign by "reference" to a class field in C#.
I have the following example to consider:
public class X
{
public X()
{
string example = "X";
new Y(ref example);
new Z(ref example);
System.Diagnostics.Debug.WriteLine(example);
}
}
public class Y
{
public Y( ref string example )
{
example += " (Updated By Y)";
}
}
public class Z
{
private string _Example;
public Z(ref string example)
{
this._Example = example;
this._Example += " (Updated By Z)";
}
}
var x = new X();
When running the above code the output is:
X (Updated By Y)
And not:
X (Updated By Y) (Updated By Z)
As I had hoped.
It seems that assigning a "ref parameter" to a field loses the reference.
Is there a way to keep hold of the reference when assigning to a field?
As others have noted, you cannot have a field of "ref to variable" type. However, just knowing that you cannot do it is probably unsatisfying; you probably also want to know first, why not, and second, how to get around this restriction.
The reason why is because there are only three possibilities:
1) Disallow fields of ref type
2) Allow unsafe fields of ref type
3) Do not use the temporary storage pool for local variables (aka "the stack")
Suppose we allowed fields of ref type. Then you could do
public ref int x;
void M()
{
int y = 123;
this.x = ref y;
}
and now y can be accessed after M completes. This means that either we're in case (2) -- accessing this.x will crash and die horribly because the storage for y no longer exists -- or we're in case (3), and the local y is stored on the garbage collected heap, not the temporary memory pool.
We like the optimization that local variables be stored on the temporary pool even if they are being passed by ref, and we hate the idea that you could leave a time bomb around that could make your program crash and die later. Therefore, option one it is: no ref fields.
Note that for local variables that are closed-over variables of anonymous functions we choose option (3); those local variables are not allocated out of the temporary pool.
Which then brings us to the second question: how do you get around it? If the reason you want a ref field is to make a getter and setter of another variable, that's perfectly legal:
sealed class Ref<T>
{
private readonly Func<T> getter;
private readonly Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value { get { return getter(); } set { setter(value); } }
}
...
Ref<int> x;
void M()
{
int y = 123;
x = new Ref<int>(()=>y, z=>{y=z;});
x.Value = 456;
Console.WriteLine(y); // 456 -- setting x.Value changes y.
}
And there you go. y is stored on the gc heap, and x is an object that has the ability to get and set y.
Note that the CLR does support ref locals and ref returning methods, though C# does not. Perhaps a hypothetical future version of C# will support these features; I have prototyped it and it works well. However, this is not real high on the priority list, so I wouldn't get my hopes up.
UPDATE: The feature mentioned in the paragraph above was finally implemented for real in C# 7. However, you still cannot store a ref in a field.
No. ref is purely a calling convention. You can't use it to qualify a field. In Z, _Example gets set to the value of the string reference passed in. You then assign a new string reference to it using +=. You never assign to example, so the ref has no effect.
The only work-around for what you want is to have a shared mutable wrapper object (an array or a hypothetical StringWrapper) that contains the reference (a string here). Generally, if you need this, you can find a larger mutable object for the classes to share.
public class StringWrapper
{
public string s;
public StringWrapper(string s)
{
this.s = s;
}
public string ToString()
{
return s;
}
}
public class X
{
public X()
{
StringWrapper example = new StringWrapper("X");
new Z(example)
System.Diagnostics.Debug.WriteLine( example );
}
}
public class Z
{
private StringWrapper _Example;
public Z( StringWrapper example )
{
this._Example = example;
this._Example.s += " (Updated By Z)";
}
}
You forgot to update the reference in the Z class:
public class Z {
private string _Example;
public Z(ref string example) {
example = this._Example += " (Updated By Z)";
}
}
Output: X (Updated By Y) (Updated By Z)
Point to keep in mind is that the += operator for a string calls the String.Concat() method. Which creates a new string object, it doesn't update the value of a string. String objects are immutable, the string class doesn't have any methods or fields that lets you change the value. Very different from the default behavior of a regular reference type.
So if you use a string method or operator, you always have to assign the return value back to a variable. This is pretty natural syntax, value types behave the same way. Your code would be very similar if you used an int instead of a string.
I was wondering how one could store a reference to an object in .net.
That is, I would like something like the following code (note, of course, that the following code may be way off from how to actually do it):
class Test
{
private /*reference to*/ Object a;
public Test(ref int a)
{
this.a = a;
this.a = ((int)this.a) + 1;
}
public Object getA() { return this.a; }
}
/*
* ...
*/
static void Main(string[] args)
{
int a;
a=3;
Test t = new Test(ref a);
Console.WriteLine(a);
Console.WriteLine(t.getA());
Console.ReadKey();
}
To produce the following output:
4
4
Ideally, I would like to do this without writing a wrapper class around the integer.
In other words, I think I want pointers in .Net.
You cannot store references to variables in .NET, period. You can store references to objects, but not references to variables.
The reason is that if you were allowed to store references to arbitrary variables then you could store references to local variables. If you can store references to local variables then the runtime cannot use the optimization of storing local variables on the short-lived memory pool, aka, the stack.
Now, even if you could do that, the operation you are describing is not typesafe for a different reason. You have a (very badly named) field variable "a" of type "reference to object variable" and a (very badly and confusingly named) local variable "a" of type "reference to int variable". Even if you could store a reference to a variable it doesn't make any sense to store a reference to an int variable in something of type "reference to object variable" because those two types are logically not compatible. The operations you can perform on them are different; a reference to an object variable can have a string written into it; a reference to an int variable cannot.
Perhaps I am misunderstanding but wouldn't a variable such as the integer above be boxed into an object which could then be stored as a reference?
You are confusing references to objects with references to variables. It is confusing that we use the same terminology for what is really two different things.
Yes, boxing turns a value type, like int, into a reference type, like object. That has ABSOLUTELY NOTHING WHATSOEVER to do with references to variables.
When you make a ref to a variable you are making an alias for that variable. When you say
void M(ref int y) { y = 123; }
...
int x = 0;
M(ref x);
you are saying "x and y are two different names for the same variable".
Now, if what you want to do is represent the notion of "I have captured a variable and I want to be able to read and write it" then use delegates:
class Ref<T>
{
private Func<T> getter;
private Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value
{
get { return getter(); }
set { setter(value); }
}
}
...
int abc = 123;
var refabc = new Ref<int>(()=>abc, x=>{abc=x;});
... now you can pass around refabc, store it in a field, and so on
refabc.Value = 456;
Console.WriteLine(abc); // 456
Console.WriteLine(refabc.Value); // 456
Make sense?
C# has no concept of a reference variable akin to C++'s int& a. There are workarounds. One is to use closures:
class Test
{
private Func<int> get_a;
private Action<int> set_a;
public Test(Func<int> get_a, Action<int> set_a)
{
this.get_a = get_a;
this.set_a = set_a;
this.set_a(this.get_a() + 1);
}
public Object getA() { return this.get_a(); }
}
/*
* ...
*/
static void Main(string[] args)
{
int a;
a=3;
Test t = new Test(() => a, n => { a = n; });
Console.WriteLine(a);
Console.WriteLine(t.getA());
Console.ReadKey();
}
I'm not in front of VS, so please excuse any embarrassing faux pas.