views:

428

answers:

6

I've got a simple function that takes a List parameter. While working with it, it copies it and reverses the copy using .NET's List(Of T).Reverse method.

Private Function FindThing(ByVal Things As List(Of Thing)) As Thing
    Dim ReverseOrderThings As List(Of Thing) = Things
    ReverseOrderThings.Reverse()
    For Each t As Thing In ReverseOrderThings
        ...
    Next
    Return Nothing
End Function

My parameter is defined as ByVal. But, it seems that ByVal does not prevent the code in the procedure from changing the list's order.

Dim Things As List(Of Thing) = GetSortedListFromSomewhere()
Dim FoundThing As Thing = FindThing(Things)
For Each t As Thing In Things
    ...
    'OMG! My Things are in reverse order!!1! WTF?'
Next

How can I protect my list parameter in such a function?


Update:

This is the correct way to make a copy of the list.

Dim ReverseOrderThings As List(Of Thing) = New List(Of Thing)(Things)

Now the list passed as a parameter is unaffected by the Reverse() method.

+6  A: 

Make a copy of the list.

The function can't change the value of the list, and in fact it is not. It is changing what the list holds, which is allowed. The only disallowed would be assigning the variable to refer to a new list.

RossFabricant
+3  A: 

In order to protect the list you will need to make a copy of it before sorting.

Things = New List(Of Thing)(Things)
JaredPar
See Andrew Hare's answer for imo the best explanation of _why_ you need this copy. The _reference_ is passed by value, but it still refers to the same object.
Joel Coehoorn
+1  A: 

You cannot directly protect it.

Since List(Of Thing) is a reference type (a class), it's passing the reference ByVal, but the contents of the list are still changable from within your routine (not the List reference itself, but what the list contains).

To protect the original list, you will need to copy it into a new collection, and sort that collection. If the list contains a reference type (Thing), this will be relatively inexpensive.

Reed Copsey
+3  A: 

Even though the list is passed ByVal it is the reference itself that is passed ByVal therefore you are copying the location of the list which, when used, is the same list object. I agree with rossfabricant that you ought to create a copy of the list yourself.

Andrew Hare
Perfect explanation. Thanks.
Zack Peterson
A: 

Your parameter passes the reference to the list by value, not the list itself. As others have noted, you need to make a copy, LINQ's ToList() extension method will do that easily.

Richard
+1  A: 

However, if the argument is a reference type, the procedure can modify the contents or members of the underlying object.

from MSDN

So ByVal protects from modifying only value-types

abatishchev