Beginner tag question

C

Chris

Hi all,

I've recently discovered the joys of tag :) I have a ListView which is
populated with strings from a List<>, and each ListView item is linked to
the relevant object in List<> using Tag.
The ListView is on a parent form, and I have a child form which adds items
to List<>. So I pass the List<> by ref*, the relevant objects are created in
the List<> and the ListView is updated in the parent form.
I'm now trying to edit items in the ListView. If an item is selected, then
ListView.SelectedItems[0].Tag is used to get the object to edit. I need this
object passed to the child form, repopulating the relevant fields to allow
for editing. I can't seem to pass the object in
ListView.SelectedItems[0].Tag, but I if I create a temp object, assign
ListView.SelectedItems[0].Tag to this, pass this object to the child form,
and assign it back to ListView.SelectedItems[0].Tag it seems to work e.g.:

if (lvMainList.SelectedItems[0].Tag is Journal)
{
Journal temp =
((Journal)lvMainList.SelectedItems[0].Tag);
JournalEntryForm journalEntry
= new JournalEntryForm(ref temp);

lvMainList.SelectedItems[0].Tag = temp;

journalEntry.ShowDialog();

journalEntry.Dispose();
}

Is this an ok way to do this, or is there a more appropriate way? Also, what
happens to the old journal object when I reassign temp to the same Tag? Is
it garbage collected? Or does this waste memory?

Sorry for all the (perhaps obvious) questions! Any help would be greatly
appreciated :)

Chris



*as the list is ref type, is it passed by ref by anyway? I used the ref
keywords to be explicit - is this overkill?
 
B

Bruce Wood

The problem is that you are passing by "ref". First, an explanation of
why you can't pass Tag by "ref", then an explanation of why you
shouldn't be using "ref".

Tag is a property of ListViewItem. That means that there (may be / is)
code in the get and set methods of the property: the property may not
map directly onto a field inside the class. In this case, it probably
does, but in the general case, a property may not even _have_ a field
behind it: it may be calculated from other fields, and setting it may
set multiple other fields. Given this, there's really no way to pass a
"pointer to" a property, because the property may not represent a
specific physical thing within the class.

You got around this by assigning the property's value to a temporary
variable, then passing that variable by "ref" (which works, because the
variable has a location on the stack, so you can "ref"er to that
location), the setting the property's value back to the value of your
temporary variable.

However, you don't need to do any of this. I think that you
misunderstand how things are passed around in .NET, and when you need
"ref". Jon Skeet has an excellent article here:

http://www.yoda.arachsys.com/csharp/parameters.html

The bottom line, in your case, is that you need to pass your List<> by
"ref" _only if you want to change it out for a whole new list_. You
need to pass the object that Tag refers to by "ref" _only if you want
to replace the whole object instance with a new instance_.

If you just want to manipulate the List<>, or change properties of the
object that Tag refers to, then you don't need "ref" at all. When you
pass a reference type (like a List<>) to a method, what is passed is a
reference to that object, so the method that you call will be working
with exactly the same object as the caller is. There is no copying
going on, so any changes that the method makes to the object (whether
it be a list or an individual object) will still be there when the
method returns.

You can read Jon's article for a more in-depth explanation.

As for your last two questions:

"What happens to the old journal object when I reassign temp to the
same Tag? Is it garbage collected? Or does this waste memory?"

Well, since the journal object that you originally got from the Tag
property is the same one you're assigning back to the Tag property,
there is no garbage collection involved at all.

Even if there were, I doubt very much that it would be enough to cause
any worry.

"As the list is ref type, is it passed by ref by anyway?"

Well, a reference to it is passed by value (see Jon's article). So it's
sort of passed by reference, in a way. (He says, ducking Jon's swing.)

"I used the ref keywords to be explicit - is this overkill?"

Yes, because adding "ref" means something else: it means that you want
to give the method you're calling the option to replace the object
instance with a whole new instance, in addition to just modifying
properties of the object. So, in your case, it's allowing the method to
replace the list of journals with a whole different list of journals.
If I'm correct in my understanding that you just want the method to be
able to change the contents of the list (but still keep the same list
object) then yes, it's overkill for what you want.

In a very few situations it can be useful, though.
 
C

Chris

Hi Bruce,
Thankyou for the detailed post and for the great article. I understand what
I'm doing now, and what I was doing wrong :)
Out of curiosity, what few situations could it be useful in?

Regards,

Chris
 
J

Jon Skeet [C# MVP]

Chris said:
Thankyou for the detailed post and for the great article. I understand what
I'm doing now, and what I was doing wrong :)
Out of curiosity, what few situations could it be useful in?

In a few situations, it genuinely makes sense for a method to return
two values. In those situations, an out parameter is often used. For
instance, Double.TryParse attempts to parse a string and "return" a
value in the out parameter, but may fail and return false (setting the
out parameter to 0) if the parsing fails.

In some other situations, it makes sense to pass something in and
potentially change it. In my experience this is somewhat rarer, and I
can't immediately think of any good examples - where possible, I'd
suggest returning the new value rather than having a ref parameter. If
the method already returns something else, of course, that's when it
might make sense.
 
B

Bruce Wood

I just searched my entire .NET project base, and found three places in
which I use "ref". These fall into the following two categories:

1. A method is being called repeatedly (or recursively) and needs to
maintain some sort of "state" just for that method. For example, I have
a pair of mutually recursive methods that build a predicate (one that
builds OR relations and one that builds AND relations) and they need to
maintain a count of how many terms have already been added to the
predicate as they walk up and down the expression tree. True, I could
have created a whole separate class to do this and made the two "ref"
parameters into object state, but I was lazy and used the good ol'
procedural programming method. So, I guess this situation doesn't
really count because it was just sloth on my part.

2. A method needs to add some stuff to an array. This is very rare in
..NET as it's usually better to use ArrayList (or even better, in
VS2005, List<T>), but in one case, for particular reasons, I have a
method that adds more stuff to the end of an array. Since arrays can't
be expanded, I have to give the method the option to replace the array
with a bigger one.
 
C

Chris

I've got a question which relates to this.

I have a form which displays a lists items like a database record - it's
navigation looks like a bindingNavigator control.
The idea is to have a quick browser of all items data, with the added
functionality of being able to view specific record types or all.
To allow a textbox to show "x (of y)" x being the current record and y being
the total number of records, do I need another list to store specific
journals in?
When I display all journals I could just use the list being passed in. But
if the user selects a specific type, I loop through the passed list and any
journals of that type are added to a tempList, and the contents of this list
displayed. Am I going about this the wrong way? It's the only way I could
think of to preserve an index as described above. By copying the entries of
one list to another, I'm making full copies of those items or am I making a
reference to the entries of the other list? This is slightly confusing me.
If I am making full copies, is there any way to pass items of one list to
another as references, so the new list items point to the relevant index of
the old list? If not, is there any easier way to do what I'm doing without
using lots of memory?

Chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

show changes in Listview? 11
drag and drop issue 4
ToString and FromString 10
Create List in Linq 4
GC collection question... 5
Which wireless gaming mouse to buy ? 7
Linq. Join. 2
Passing an array to Tag property 3

Top