By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
429,480 Members | 767 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 429,480 IT Pros & Developers. It's quick & easy.

Object References - got a blackout

P: n/a
Hi all,

I've got a little hole in my head concerning references. Here's what
I'm trying to do: I'm calling a function, passing the reference of a
business object for editing. The function clones the object, calls an
editor dialog to let the user edit the object, and then - depending on
the DialogResult - assigns either the clone/backup copy or the modified
object itself to the reference. Maybe I'm thinking too much in pointer
references - but isn't it possible to alter a reference (not the
referenced object) like this:

public static bool EditMyObject(ref MyObject o)
{
MyObject o2 = o.Clone();
if (...) {
o = ...
} else { // return backup copy
o = o2;
}
}

In this case, the result would always be the original o instance, never
o2.

Please, untie the knot in my brain ;-) - thank you in advance,

Phil

Nov 20 '06 #1
Share this Question
Share on Google+
14 Replies


P: n/a
"Philipp Reif" <ph**********@gmail.comwrote in message
news:11**********************@h54g2000cwb.googlegr oups.com...
[...]
In this case, the result would always be the original o instance, never
o2.
"Would always be"? Why do you say that?

It seems to me that what you want and the code you posted are the same. You
can indeed pass a reference variable by reference to a function, and modify
the reference. In your example, if you set the local parameter variable "o"
to some new reference, the variable used as the parameter by the caller will
be changed to refer to that same reference.

What is not working as you expect it to?

Pete
Nov 20 '06 #2

P: n/a
Thanks for your assistance, Pete.
It seems to me that what you want and the code you posted are the same. You
can indeed pass a reference variable by reference to a function, and modify
the reference.
Well, exactly that is not working. I'm passing a ref to instance A to
the function, the ref is modified inside the function to point to a
clone of A, but as the function returns, the original instance is still
being used. That's why I asked - I've been coding now for 16 years,
and I really doubted my abilities as I came across this.

I could post the complete original code here, if that would help.

Phil

Nov 20 '06 #3

P: n/a
Hi Philipp,
In this case, the result would always be the original o instance, never
o2.
Not following you 100% on this one, but it looks like what you are trying to
do is pass in an object and then let the user modify the object, they can
then back out of the changes or commit the changes. In C# parameters are
passed by value, even though the underlying type could be passed by reference
i.e.

Given a Person class, this is a reference type since it is not inheriting
from System.ValueType:

class Person
{
private string name;

public Person(string name)
{
this.name = name;
}

public string Name
{
get
{
return this.name;
}
}
}

If we create an instance of a person, and pass it to a function without
using the ref keyword the person instance is passed by reference (i.e. inside
the function the parameter is refering to the same instance of the object
that was passed into the function) but we cannot change what the reference
outside the function is pointing to since the parameter itself was copied
when the function was called:

class Person
{
private string name;

public Person(string name)
{
this.name = name;
}

public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
}

class Program
{
static void Main(string[] args)
{
Person p1 = new Person("frank");
ChangePersonName1(p1);
//Now p1.Name == "bob"

ChangePersonName2(p1);
//Still p1.Name == "bob"

ChangePersonName3(ref p1);
//Here p1.Name == "john"
Console.ReadLine();
}

static void ChangePersonName1(Person person)
{
person.Name = "bob";
}

static void ChangePersonName2(Person person)
{
//the person parameter is a copy of the
//frank variable so if we change what the
//person variable points to we are not
//changing what the frank variable points to.
person = new Person("mark");

//here person.Name == "mark" but still p1.name == "bob"
}

static void ChangePersonName3(ref Person person)
{
//here the person variable and p1 variable are the same
//variable so changing what person refers to will change
//what p1 refers to.

person = new Person("john");

//here person.Name == "john" and p1.Name == "john"
}

I personally do not like to use the ref keyword since it can make code
confusing and not easy to follow. Instead of the code you have:

public static bool EditMyObject(ref MyObject o)
{
MyObject o2 = o.Clone();
if (...) {
o = ...
} else { // return backup copy
o = o2;
}
}
I would do something like:
public static MyObject EditMyObject(MyObject o)
{
MyObject o2 = o.Clone();

//let user modify o2 instance.
showGUI(o2);

if (userWantsToAcceptChanges)
{
return o2;
}
else
{ // return backup copy
return o;
}
}

You don't need a bool to indicate success or not (if something goes wrong
you can throw an exception), then the calling code would be something like:

MyObject myObj = new MyObject();
myObj = EditMyObject(myObj);

Also an inportant point to remember is that if you cloning an object like in
your example, you will need to make a deep copy if you are exposing any of
the properties of a object being referenced by the o2 instance, otherwise a
user could modify these references and then click cancel at which point you
would return the o instance which would be unchanged but the items references
by it could still have been modified. For value types, i.e. types deriving
from System.ValueType the object when passed to a method is shallow copied
unlike reference types, for more info, see:
http://www.yoda.arachsys.com/csharp/parameters.html

Personally when I create a GUI I normally use the Command design pattern
which gives the added benefit of allowing undo/redo and helps increase the
testability of your GUI code through unit tests.

HTH
Mark.
--
http://www.markdawson.org
"Philipp Reif" wrote:
Hi all,

I've got a little hole in my head concerning references. Here's what
I'm trying to do: I'm calling a function, passing the reference of a
business object for editing. The function clones the object, calls an
editor dialog to let the user edit the object, and then - depending on
the DialogResult - assigns either the clone/backup copy or the modified
object itself to the reference. Maybe I'm thinking too much in pointer
references - but isn't it possible to alter a reference (not the
referenced object) like this:

public static bool EditMyObject(ref MyObject o)
{
MyObject o2 = o.Clone();
if (...) {
o = ...
} else { // return backup copy
o = o2;
}
}

In this case, the result would always be the original o instance, never
o2.

Please, untie the knot in my brain ;-) - thank you in advance,

Phil

Nov 20 '06 #4

P: n/a
//the person parameter is a copy of the
//frank variable so if we change what the
//person variable points to we are not
//changing what the frank variable points to

meant to be:
//the person parameter is a copy of the
//p1 variable so if we change what the
//person variable points to we are not
//changing what the p1 variable points to

changed variable name half way through writing post :-)

--
http://www.markdawson.org
"Mark R. Dawson" wrote:
Hi Philipp,
In this case, the result would always be the original o instance, never
o2.

Not following you 100% on this one, but it looks like what you are trying to
do is pass in an object and then let the user modify the object, they can
then back out of the changes or commit the changes. In C# parameters are
passed by value, even though the underlying type could be passed by reference
i.e.

Given a Person class, this is a reference type since it is not inheriting
from System.ValueType:

class Person
{
private string name;

public Person(string name)
{
this.name = name;
}

public string Name
{
get
{
return this.name;
}
}
}

If we create an instance of a person, and pass it to a function without
using the ref keyword the person instance is passed by reference (i.e. inside
the function the parameter is refering to the same instance of the object
that was passed into the function) but we cannot change what the reference
outside the function is pointing to since the parameter itself was copied
when the function was called:

class Person
{
private string name;

public Person(string name)
{
this.name = name;
}

public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
}

class Program
{
static void Main(string[] args)
{
Person p1 = new Person("frank");
ChangePersonName1(p1);
//Now p1.Name == "bob"

ChangePersonName2(p1);
//Still p1.Name == "bob"

ChangePersonName3(ref p1);
//Here p1.Name == "john"
Console.ReadLine();
}

static void ChangePersonName1(Person person)
{
person.Name = "bob";
}

static void ChangePersonName2(Person person)
{
//the person parameter is a copy of the
//frank variable so if we change what the
//person variable points to we are not
//changing what the frank variable points to.
person = new Person("mark");

//here person.Name == "mark" but still p1.name == "bob"
}

static void ChangePersonName3(ref Person person)
{
//here the person variable and p1 variable are the same
//variable so changing what person refers to will change
//what p1 refers to.

person = new Person("john");

//here person.Name == "john" and p1.Name == "john"
}

I personally do not like to use the ref keyword since it can make code
confusing and not easy to follow. Instead of the code you have:

public static bool EditMyObject(ref MyObject o)
{
MyObject o2 = o.Clone();
if (...) {
o = ...
} else { // return backup copy
o = o2;
}
}
I would do something like:
public static MyObject EditMyObject(MyObject o)
{
MyObject o2 = o.Clone();

//let user modify o2 instance.
showGUI(o2);

if (userWantsToAcceptChanges)
{
return o2;
}
else
{ // return backup copy
return o;
}
}

You don't need a bool to indicate success or not (if something goes wrong
you can throw an exception), then the calling code would be something like:

MyObject myObj = new MyObject();
myObj = EditMyObject(myObj);

Also an inportant point to remember is that if you cloning an object like in
your example, you will need to make a deep copy if you are exposing any of
the properties of a object being referenced by the o2 instance, otherwise a
user could modify these references and then click cancel at which point you
would return the o instance which would be unchanged but the items references
by it could still have been modified. For value types, i.e. types deriving
from System.ValueType the object when passed to a method is shallow copied
unlike reference types, for more info, see:
http://www.yoda.arachsys.com/csharp/parameters.html

Personally when I create a GUI I normally use the Command design pattern
which gives the added benefit of allowing undo/redo and helps increase the
testability of your GUI code through unit tests.

HTH
Mark.
--
http://www.markdawson.org
"Philipp Reif" wrote:
Hi all,

I've got a little hole in my head concerning references. Here's what
I'm trying to do: I'm calling a function, passing the reference of a
business object for editing. The function clones the object, calls an
editor dialog to let the user edit the object, and then - depending on
the DialogResult - assigns either the clone/backup copy or the modified
object itself to the reference. Maybe I'm thinking too much in pointer
references - but isn't it possible to alter a reference (not the
referenced object) like this:

public static bool EditMyObject(ref MyObject o)
{
MyObject o2 = o.Clone();
if (...) {
o = ...
} else { // return backup copy
o = o2;
}
}

In this case, the result would always be the original o instance, never
o2.

Please, untie the knot in my brain ;-) - thank you in advance,

Phil
Nov 20 '06 #5

P: n/a
Philipp Reif <ph**********@gmail.comwrote:
Thanks for your assistance, Pete.
It seems to me that what you want and the code you posted are the same. You
can indeed pass a reference variable by reference to a function, and modify
the reference.

Well, exactly that is not working. I'm passing a ref to instance A to
the function, the ref is modified inside the function to point to a
clone of A, but as the function returns, the original instance is still
being used. That's why I asked - I've been coding now for 16 years,
and I really doubted my abilities as I came across this.

I could post the complete original code here, if that would help.
Don't post the complete original code - post a version which is cut
down to show the bare minimum which fails.

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I'm looking for.

It does sound like what you're doing should work. Mind you, I'd just
change the method to return the appropriate reference rather than using
a "ref" parameter.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 20 '06 #6

P: n/a
Hi Philipp,
like you mentioned, can you post a short but complete example which
demonstrates the problem you are having.

Thanks
Mark.
--
http://www.markdawson.org
"Philipp Reif" wrote:
Thanks for your assistance, Pete.
It seems to me that what you want and the code you posted are the same. You
can indeed pass a reference variable by reference to a function, and modify
the reference.

Well, exactly that is not working. I'm passing a ref to instance A to
the function, the ref is modified inside the function to point to a
clone of A, but as the function returns, the original instance is still
being used. That's why I asked - I've been coding now for 16 years,
and I really doubted my abilities as I came across this.

I could post the complete original code here, if that would help.

Phil

Nov 20 '06 #7

P: n/a
Mark R. Dawson <Ma*********@discussions.microsoft.comwrote:

<snip>
For value types, i.e. types deriving
from System.ValueType the object when passed to a method is shallow copied
unlike reference types, for more info, see:
http://www.yoda.arachsys.com/csharp/parameters.html
That's drawing a false distinction. For both value types and reference
types, by default the *value of the argument* is copied. It's just that
for reference types, that value is a reference.

(That's why I don't like saying that the instance of the object is
"passed by reference" - it's not. It's a similar effect, but it's not
true pass by reference.)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 20 '06 #8

P: n/a
Hi John,
that is what I meant :-) It is sometimes difficult to clearly put this
into words, hence why I pointed him to your doc which does a great job of
showing the differences :-)

Mark.
--
http://www.markdawson.org
"Jon Skeet [C# MVP]" wrote:
Mark R. Dawson <Ma*********@discussions.microsoft.comwrote:

<snip>
For value types, i.e. types deriving
from System.ValueType the object when passed to a method is shallow copied
unlike reference types, for more info, see:
http://www.yoda.arachsys.com/csharp/parameters.html

That's drawing a false distinction. For both value types and reference
types, by default the *value of the argument* is copied. It's just that
for reference types, that value is a reference.

(That's why I don't like saying that the instance of the object is
"passed by reference" - it's not. It's a similar effect, but it's not
true pass by reference.)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 20 '06 #9

P: n/a
Appologies Jon not John :-)

Mark.
--
http://www.markdawson.org
"Mark R. Dawson" wrote:
Hi John,
that is what I meant :-) It is sometimes difficult to clearly put this
into words, hence why I pointed him to your doc which does a great job of
showing the differences :-)

Mark.
--
http://www.markdawson.org
"Jon Skeet [C# MVP]" wrote:
Mark R. Dawson <Ma*********@discussions.microsoft.comwrote:

<snip>
For value types, i.e. types deriving
from System.ValueType the object when passed to a method is shallow copied
unlike reference types, for more info, see:
http://www.yoda.arachsys.com/csharp/parameters.html
That's drawing a false distinction. For both value types and reference
types, by default the *value of the argument* is copied. It's just that
for reference types, that value is a reference.

(That's why I don't like saying that the instance of the object is
"passed by reference" - it's not. It's a similar effect, but it's not
true pass by reference.)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 20 '06 #10

P: n/a
Thanks for your very detailed post! I am using the "ref" approach, and
I'm just staring at my code and try to see what's the difference
between yours and mine, as that's just what I tried.

Step by step:

1) I create a list of objects in a form: Checkliste checkliste = new
Checkliste("main");

2) I fill a TreeView with nodes. The tag of each node is one instance
of "Aufgabe".

3) User double clicks a node, and the edit dialog is called:

Aufgabe a = treeView1.SelectedNode.Tag as Aufgabe;
if (AufgabeDialog.AufgabeBearbeiten(ref a)) {
....

4) AufgabeBearbeiten looks like this:

public static bool AufgabeBearbeiten(ref Aufgabe a)
{
Aufgabe clone = a.Clone() as Aufgabe;
using (AufgabeDialog dlg = new AufgabeDialog())
{
dlg.Datensatz = clone;
if (dlg.ShowDialog() == DialogResult.OK)
{
a = dlg.Datensatz;
return true;
}
else
{
return false;
}
}
}

5) dlg.Datensatz will store a reference to the object internally and
assign it to a BindingSource.

6) AufgabeBearbeiten returns true or false, but the outer "a" is still
the original object, not the modified one.

Phil

Nov 20 '06 #11

P: n/a
As for the cloneing, I'm using a deep copy of the object.

Phil

Nov 20 '06 #12

P: n/a
Hi Philipp,
when you say:
6) AufgabeBearbeiten returns true or false, but the outer "a" is still
the original object, not the modified one.
Are you saying that based on the fact that after calling the function the
properties of "a" have not been modified, or you know they are exactly the
same instance i.e. the cloned version and original "a" have the same
GetHashCode() value (assuming you have not overriden this), so "a" has the
same hashcode before and after calling the function?

If you are basing your statment that the object is still the original object
on the fact that the values of the object are still the same take a look in
the debugger at the line after "a = dlg.Datensatz":
if (dlg.ShowDialog() == DialogResult.OK)
{
a = dlg.Datensatz;
return true;
}
and verify that the values of the cloned object are indeed updated. It may
be the case that your databinding has not updated the fields in the
underlying object. I can not see anything obviously wrong with the code, my
guess would be what I just said.

Mark.
--
http://www.markdawson.org
"Philipp Reif" wrote:
Thanks for your very detailed post! I am using the "ref" approach, and
I'm just staring at my code and try to see what's the difference
between yours and mine, as that's just what I tried.

Step by step:

1) I create a list of objects in a form: Checkliste checkliste = new
Checkliste("main");

2) I fill a TreeView with nodes. The tag of each node is one instance
of "Aufgabe".

3) User double clicks a node, and the edit dialog is called:

Aufgabe a = treeView1.SelectedNode.Tag as Aufgabe;
if (AufgabeDialog.AufgabeBearbeiten(ref a)) {
....

4) AufgabeBearbeiten looks like this:

public static bool AufgabeBearbeiten(ref Aufgabe a)
{
Aufgabe clone = a.Clone() as Aufgabe;
using (AufgabeDialog dlg = new AufgabeDialog())
{
dlg.Datensatz = clone;
if (dlg.ShowDialog() == DialogResult.OK)
{
a = dlg.Datensatz;
return true;
}
else
{
return false;
}
}
}

5) dlg.Datensatz will store a reference to the object internally and
assign it to a BindingSource.

6) AufgabeBearbeiten returns true or false, but the outer "a" is still
the original object, not the modified one.

Phil

Nov 20 '06 #13

P: n/a
I think I've got a trace. Checkliste is a descendant of List<Aufgabe>,
and if I replace that with a plain array of Aufgabe objects, everything
works as expected and exactly as all of you pointed out. I'll have a
look at List<Tnow to see why that happens.

Thanks, Phil

Nov 20 '06 #14

P: n/a
Mark,
Are you saying that based on the fact that after calling the function the
properties of "a" have not been modified, or you know they are exactly the
same instance i.e. the cloned version and original "a" have the same
GetHashCode() value (assuming you have not overriden this), so "a" has the
same hashcode before and after calling the function?
I didn't have a look at GetHashCode(), admittedly. Here's the trace:

checkliste[0] before edit: 19634871
a before edit: 19634871
clone: 22584602
clone after edit: 22584602
a before clone assinged: 19634871
a after clone assinged: 22584602
a after edit: 22584602
checkliste[0] after edit: 19634871

So here's the thing, I think - checkliste[0] contains the same object
reference as a, but if I change a's reference, checkiste[0]'s reference
wouldn't be updated. Now that I look at it, it's logical - thanks a
billion times for pointing me into the right direction, I was really
standing in my own feet...

Guess it's time for a coffee now...

Phil

Nov 20 '06 #15

This discussion thread is closed

Replies have been disabled for this discussion.