Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to deal with ParamArray values as byRef so they can be updated?

Sounds simple enough, but its not working. In this example, I want to set the values of 3 fields to equal a 4th. I could do something like this....

Dim str1 As String = "1"
Dim str2 As String = "2"
Dim str3 As String = "3"
Dim str4 As String = "4"

str2 = str1
str3 = str1
str4 = str1

... but that's kind of wordy (yeah, I know, vb is wordy in most cases). I would like to have something I can use to reduce this to a single line call, so I made this extension method.

Module Module1

    Sub Main()

        Dim str1 As String = "1"
        Dim str2 As String = "2"
        Dim str3 As String = "3"
        Dim str4 As String = "4"

        Console.WriteLine("Extension method return value = {0}", str1.SetEqual(str2, str3, str4))
        Console.WriteLine("String 1 = {0}", str1)
        Console.WriteLine("String 2 = {0}", str2)
        Console.WriteLine("String 3 = {0}", str3)
        Console.WriteLine("String 4 = {0}", str4)

        Console.ReadKey()

    End Sub

    <System.Runtime.CompilerServices.Extension()> _
    Public Function SetEqual(Of T)(ByVal source As T, _
                                   ByVal ParamArray targets() As T) _
                                   As T

        For _index = 0 To targets.Length - 1
            targets(_index) = source
            Console.WriteLine("Target Value {0} = {1}", _index, targets(_index))
        Next

        Return source

    End Function

End Module

Seems straightforward enough, right? Well, the output is this...

Target Value 0 = 1
Target Value 1 = 1
Target Value 2 = 1
Extension method return value = 1
String 1 = 1
String 2 = 2
String 3 = 3
String 4 = 4

Values in the param array did not get updated in the return! I was expecting to have all of the final values now be "1", like they are in the Function.

Is there any way to get an update-able ParamArray collection like this? ParamArray must be declared ByVal, but with a reference type like String, shouldn't that only make a copy of the pointer and allow me to change the underlying value?

Is there a better way to get what I want? (C# is not an option for this).

like image 594
StingyJack Avatar asked Mar 16 '09 12:03

StingyJack


1 Answers

What you're trying to do cannot be achieved with ParamArray. When you call a ParamArray method the following occurs under the hood

  1. CLR allocates an array of appropriate length
  2. The values are then copied into the array
  3. Array is passed down into the function

There is no post call operation that will copy the values back out of the array and into the original variables that were passed in.

The only reliable way to have the function modify a value and have it seen at the call site is to pass the value ByRef. You could do a bit of magic to have a set of overloads which take ByRefs, manually convert to an array and then does a copy back. But that's the closest you're going to get.

like image 148
JaredPar Avatar answered Nov 02 '22 06:11

JaredPar