F
Francois Appert
This post was originally in the C# Corner site, but their server is
down. I'd like to see if this group can answer.
I program in C++ and am learning C#.
The issue is: why should anybody bother in C# with pass-by-reference
using the "ref" keyword or "out" for objects in a method parameter
list, when, after all, it appears in C# that for all intents and
purposes a reference is always being passed, rather than the real
object (with, it seems, the exception of data primitives like int,
which are not 'boxed').
The reply from C# Corner by a poster, call him Brian, as to why 'ref'
is needed was to write out a simple demonstration program (see below),
which indeed seems to refute the above, and point out that unless you
use keyword "ref" in your method parameter, then you cannot change an
object passed to a method while inside the method.
However--and this is the point of this post--it seems I've found a
workaround so that even with the use of "pass by value", you can
indeed change an object passed, inside the called method (when you
exit the method), if you use the assignment operator "=" and return a
new object (see below, at the comments ////). I don't think what's
known in C++ as 'aliasing' is an issue here when doing this
"workaround" (correct me if I'm wrong). That's really the point of
this post--can you have 'data aliasing' when you pass-by-value in C#,
since we're always dealing with references, and in theory it's
supposed to be safe? Is there any other potential problem to my
'workaround' below, as a coding style?
Any comments? Why do we need 'ref' after all?
Fran
// start of console C# program
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyObject A = new MyObject();
A.AMember = 1;
Methods.PassObjectByValue1(A);
Console.WriteLine(A.AMember);// 2 // That is, output is '2'
MyObject B = new MyObject();
B.AMember = 1;
Methods.PassObjectByValue2(B);
Console.WriteLine(B.AMember);// 1 //That is, output is '1' (not '2')
// while the above line 'proves' Brian's point, the 'change' below
(workaround) rebuts it?!
//////////////////////////////////////////////////
//change made here! "workaround"
B = Methods.PassObjectByValueTWO(B); //note use of "=" assignment
operator
//change object via pass by value? Yes! output is indeed
'2' not '1'
Console.WriteLine("B.AMember should equal TWO!: {0}",B.AMember);
// end of change made
/////////////////////////////////////////////////
/* rest of this listing shows how 'ref' superior when you want to
'change' the object--this is disputed above */
MyObject C = new MyObject();
C.AMember = 1;
Methods.PassObjectByRef1(ref C);
Console.WriteLine(C.AMember);// 2
MyObject D = new MyObject();
D.AMember = 1;
Methods.PassObjectByRef2(ref D);
Console.WriteLine(D.AMember);// 2
Console.ReadKey();
}
}
class MyObject
{
public int AMember;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// start of seperate source file now; // start of "Methods" class used
above
class Methods
{
public static void PassObjectByValue1(MyObject X)
{
// I can change the values of member of an
// parameter of a reference type passed by value
X.AMember = 2;
}
public static void PassObjectByValue2(MyObject X)
{
//I can't change the object
// THIS IS THE PART 'disputed' AND THE SUBJECT OF THE 'workaround'
above
X = new MyObject();
X.AMember = 2;
// the point by Brian being, that AMember = 2 here but still = 1
outside here
}
/////////////////////////////////////////// YES YOU CAN! ('workaround'
to above)
// add this function to the class Methods--
public static MyObject PassObjectByValueTWO (MyObject X)
{
//you can change the object!
MyObject WhyNot = new MyObject();
WhyNot.AMember = X.AMember + 1; //2
//now AMember is 2 here, and soon to be '2' outside too
return WhyNot; //returns object of type MyObject (this is the
key)
}
////////////////////////////////////////// END OF YES YOU CAN!
public static void PassObjectByRef1(ref MyObject X)
{
// I can change the values of member of an
// parameter of a reference type passed by ref
X.AMember = 2;
}
public static void PassObjectByRef2(ref MyObject X)
{
//I can also change the object that is referenced
X = new MyObject();
X.AMember = 2;
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
down. I'd like to see if this group can answer.
I program in C++ and am learning C#.
The issue is: why should anybody bother in C# with pass-by-reference
using the "ref" keyword or "out" for objects in a method parameter
list, when, after all, it appears in C# that for all intents and
purposes a reference is always being passed, rather than the real
object (with, it seems, the exception of data primitives like int,
which are not 'boxed').
The reply from C# Corner by a poster, call him Brian, as to why 'ref'
is needed was to write out a simple demonstration program (see below),
which indeed seems to refute the above, and point out that unless you
use keyword "ref" in your method parameter, then you cannot change an
object passed to a method while inside the method.
However--and this is the point of this post--it seems I've found a
workaround so that even with the use of "pass by value", you can
indeed change an object passed, inside the called method (when you
exit the method), if you use the assignment operator "=" and return a
new object (see below, at the comments ////). I don't think what's
known in C++ as 'aliasing' is an issue here when doing this
"workaround" (correct me if I'm wrong). That's really the point of
this post--can you have 'data aliasing' when you pass-by-value in C#,
since we're always dealing with references, and in theory it's
supposed to be safe? Is there any other potential problem to my
'workaround' below, as a coding style?
Any comments? Why do we need 'ref' after all?
Fran
// start of console C# program
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyObject A = new MyObject();
A.AMember = 1;
Methods.PassObjectByValue1(A);
Console.WriteLine(A.AMember);// 2 // That is, output is '2'
MyObject B = new MyObject();
B.AMember = 1;
Methods.PassObjectByValue2(B);
Console.WriteLine(B.AMember);// 1 //That is, output is '1' (not '2')
// while the above line 'proves' Brian's point, the 'change' below
(workaround) rebuts it?!
//////////////////////////////////////////////////
//change made here! "workaround"
B = Methods.PassObjectByValueTWO(B); //note use of "=" assignment
operator
//change object via pass by value? Yes! output is indeed
'2' not '1'
Console.WriteLine("B.AMember should equal TWO!: {0}",B.AMember);
// end of change made
/////////////////////////////////////////////////
/* rest of this listing shows how 'ref' superior when you want to
'change' the object--this is disputed above */
MyObject C = new MyObject();
C.AMember = 1;
Methods.PassObjectByRef1(ref C);
Console.WriteLine(C.AMember);// 2
MyObject D = new MyObject();
D.AMember = 1;
Methods.PassObjectByRef2(ref D);
Console.WriteLine(D.AMember);// 2
Console.ReadKey();
}
}
class MyObject
{
public int AMember;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// start of seperate source file now; // start of "Methods" class used
above
class Methods
{
public static void PassObjectByValue1(MyObject X)
{
// I can change the values of member of an
// parameter of a reference type passed by value
X.AMember = 2;
}
public static void PassObjectByValue2(MyObject X)
{
//I can't change the object
// THIS IS THE PART 'disputed' AND THE SUBJECT OF THE 'workaround'
above
X = new MyObject();
X.AMember = 2;
// the point by Brian being, that AMember = 2 here but still = 1
outside here
}
/////////////////////////////////////////// YES YOU CAN! ('workaround'
to above)
// add this function to the class Methods--
public static MyObject PassObjectByValueTWO (MyObject X)
{
//you can change the object!
MyObject WhyNot = new MyObject();
WhyNot.AMember = X.AMember + 1; //2
//now AMember is 2 here, and soon to be '2' outside too
return WhyNot; //returns object of type MyObject (this is the
key)
}
////////////////////////////////////////// END OF YES YOU CAN!
public static void PassObjectByRef1(ref MyObject X)
{
// I can change the values of member of an
// parameter of a reference type passed by ref
X.AMember = 2;
}
public static void PassObjectByRef2(ref MyObject X)
{
//I can also change the object that is referenced
X = new MyObject();
X.AMember = 2;
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////