VB.NET, Is Object Returned by Reference from Funct

2020-03-03 05:02发布

问题:

This should be a fairly common question, but I haven't found a straightforward answer anywhere.

If I instantiate an object within a function in VB.NET and return it, does it return it by reference or by value. IE - should I be worried about performance if I write something like this:

Public Function ret_obj_func() As big_object
    Dim ret_obj As New big_obj(<lots of stuff>)
    Return ret_obj
End Function

If I call this function from somewhere else, will it instantiate the object in the ret_obj and then create a deep copy to pass back a copy to the caller, Or will it just pass back a reference?

回答1:

It just passes back a reference (assuming big_obj is a class). I wouldn't use the term "by reference" here, as that has a subtly different meaning when it comes to parameter passing - but assuming big_obj is a class - a reference type - the value of ret_obj is a reference, and that reference will be what's returned.

I don't have any articles on this from a VB perspective, but if you're happy to look at C#, you may find these articles useful:

  • Reference and value types
  • Parameter passing in C#


回答2:

There are two dichotomous issues here with similar vocabulary involved: value versus reference types, and passing variables by value versus by reference.

Value v. Reference Types

The first issue is value versus reference types. Value types are passed around through copying - usually. The value types are:

  1. Date
  2. Char
  3. U/Int(16/32/64)
  4. Decimal
  5. Single and Double
  6. Boolean
  7. Structs
  8. Enums

All but the above-listed types are reference types. When an object gets passed around, what is actually being passed is its memory address, which is often thought of as an int on 32 bit platforms and a long on 64 bit platforms.


Passing by Value v. By Reference

The second issue is passing a variable by value versus reference.

A variable is a slot at a certain position in memory that can hold stuff. For value types, it holds the actual value. For reference types, it holds the memory address of the object on the heap (or is Nothing).

By Value

When you pass a variable by value, whatever is at that variable's memory location is what gets copied. For value types, that means the value itself is copied. For reference types, what gets copied is the memory address of the object refered to by the variable.

By Reference

Remember that a variable is just a slot in memory for holding stuff. When you pass a variable by reference, you are passing the address of that slot (as opposed to the data in that slot).

If that variable is a value type, that slot holds the value itself, so the thing being passed is a pointer to the value.

If that variable is a reference type, the slot is holding a pointer to the object's location in memory, so the thing being passed is a pointer to your variable (just like with value types), which itself contains another pointer (not like value types) which leads to the memory location that holds the object referred to by the variable.

This allows a function to modify a variable in another function, like this:

Sub IPassByReference
   Dim myVariable As Boolean = False
   IReceiveByReference myVariable
   Debug.Print(myVariable.ToString()) 'Always prints True
End Function

Sub IReceiveByReference(ByRef flag As Boolean)
   flag = True 'the memory address of myVariable was passed.
End Function

Let's compare to the situation where you pass by value:

Sub IPassByValue
   Dim myVariable As Boolean = False
   IReceiveByValue myVariable 
   Debug.Print(myVariable.ToString()) 'Always prints False
End Function

Sub IReceiveByValue(ByVal flag As Boolean)
   flag = True 'the value of myVariable was passed.
End Function

In the above example, Boolean is a value type. If it were an object, IReceiveByReference would have the power to point myVariable to an entirely new object, because it received the address of myVariable - not the address of the object to which myVariable points. By contrast, IReceiveByValue was only passed the contents of myVariable, so it cannot change myVariable to point to a new object. It could still change the object by setting its fields and properties and calling its methods, though.

Return By-Reference?

Although functions can pass variables by reference, they cannot return them that way. When a function returns, its local variables do not exist anymore (or are pending cleanup if they are heap-allocated). Functions therefore always return by value; because the local variables don't have valid memory addresses anymore, there aren't any variable references to return.

Putting it all together, when you return an object from a function, the only thing that is copied is the address of the object. When you return a value type from a function, the value itself is copied.

This means reference types are essentially value types, wherein the value is the memory address of an object on the heap, (or Nothing).



回答3:

VB.NET does not have the ability to return by reference. Neither does C# for that matter, but it has been proposed. What you actually get back is just a reference to the object. So to precisely define this it returns a reference to the object. It does not return by reference like what you might compare to the ByRef keyword.