When does a ByVal argument actually become ByVal ?

chris_asa

Active member
Joined
Sep 4, 2009
Messages
26
Location
Switzerland
Programming Experience
10+
I'm using a BackgroundWorker and passing a class° as argument. BackgroundWorker arguments are perforce ByVal. In principle, this leaves me free to play with the original class in the UI thread without hurting the ByVal "clone" being processed by the BackgroundWorker.

BUT!

My experiments suggest that the ByVal class argument is not "materialized" until the BackgroundWorker actually reads the args.

EXAMPLE if BackgroundWorker has Thread.Sleep(2000) BEFORE reading the args (ByVal class) AND the UI thread modifies its instance of the class during that 2 seconds, the BackgroundWorker instance of the class IS MODIFIED when the args are eventually collected.

The first thing I want to do in the UI thread after spawning the BackgroundWorker is to clear the original class instance. On a busy machine, I can imagine a situation where the BackgroundWorker takes some time to "get off the ground". It would be an unimaginable disaster for my application if clearing the UI-instance of the class destroyed the data that the BackgroundWorker was supposed to handle.

A possible workaround is for the Backgroundworker to UpdateProgress after it has read the args, and for the UI thread to wait for this progress update before it clears the class.

Are my experiments flawed ?
or is the ByVal argument really only "materialized" after reading the args ?
or (worse for my intended use) is the supposed ByVal argument not truly ByVal at all ?
If ByVal actually is ByVal but only when the args are read, is there a better workaround than the progress update ?

regards Chris


° Probably not relevant, but my class is a parent class containing 5 child classes. Two of the child classes contain a datatable. Overall it can be quite a "heavy" object: one of the datatables has typically 10...100 rows - 32k rows are allowed, but never reached in reality.
 
Last edited:
It's a little hard to say, and even though this really sounds like a weird optimization (have you tried turning compile-time optimizations on or off?) issue, please post some code so we can test it out.
 
ByVal class argument
A class is a reference type, passing that ByVal only means the reference is copied, so you will have two references pointing to same object. Only a value type will have its value copied through a ByVal parameter.
or is the ByVal argument really only "materialized" after reading the args ?
It happens at the exact moment the method is called and the parameter is passed. A parameter is just like a variable, when the call is executed it is set.
if clearing the UI-instance of the class destroyed the data that the BackgroundWorker was supposed to handle
You can dereference the variable that was passed, ie set it to Nothing or set it to reference a different object, without that having any effect on the new reference (to passed object) that is held by the method it was passed to.
 
ByVal and ByRef relate to the original variable, NOT the original object. When a parameter is passed ByVal, the contents of the original variable is copied. If the original variable is a value type then that is a copy of a value. If the original variable is a reference type then that is a copy of a reference. When a parameter is passed ByRef, a reference to the variable is created. If the original variable is a value type then that is a reference to a value. If the original variable is a reference type then that is a reference to a reference. Here is a simple summary of what you can do when:

Value type passed ByVal: no changes made to the parameter in the method affect the original variable.
Value type passed ByRef: editing the parameter has no effect on the original variable but assigning a new value to the parameter is reflected in the original variable.
Reference type passed ByVal: assigning a new object to the parameter has no effect on the original variable but editing the parameter is reflected in the original variable.
Reference type passed ByRef: assigning a new object to the parameter and editing the parameter are both reflected in the original.

When I say "editing" I mean setting fields and/or properties. Basically, there is no way to prevent a method making changes to a reference type object passes to a parameter. If you don't want an original object changed then you would have to make a copy yourself first and then pass that into the method.
 
Thanks for the replies.

I knew it worked like that in the UI-Thread, but I had naïvely convinced myself that it would somehow be different when an object was passed to a different thread.

Making a copy of the object is an annoying solution. I don't have any use for the data in the UI-thread object after it has been passed to the background thread - quite the opposite in fact: the whole motive for the background thread is to allow the UI-thread to start building the next object whilst the old object is being processed in the background.

These comments give me hope:

JohnH
You can dereference the variable that was passed, ie set it to Nothing or set it to reference a different object, without that having any effect on the new reference (to passed object) that is held by the method it was passed to.

jmcilhinney
Reference type passed ByVal: assigning a new object to the parameter has no effect on the original variable but editing the parameter is reflected in the original variable.

Experiments continue...

Thanks again. Chris
 
Back
Top