Есть ли способ обработать значения ParamArray как byRef, чтобы они могли быть обновлены? - PullRequest
4 голосов
/ 16 марта 2009

Звучит достаточно просто, но не работает. В этом примере я хочу установить значения 3 полей равными 4-му. Я мог бы сделать что-то вроде этого ...

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

... но это довольно многословно (да, я знаю, в большинстве случаев vb многословно). Я хотел бы иметь что-то, что я могу использовать, чтобы свести это к вызову одной строки, поэтому я сделал этот метод расширения.

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

Кажется, достаточно просто, верно? Ну, вывод такой ...

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

Значения в массиве параметров не обновляются при возврате! Я ожидал, что все конечные значения теперь будут равны «1», как в функции.

Есть ли способ получить коллекцию ParamArray с возможностью обновления, подобную этой? ParamArray должен быть объявлен ByVal, но со ссылочным типом, таким как String, разве это не должно сделать только копию указателя и позволить мне изменить базовое значение?

Есть ли лучший способ получить то, что я хочу? (C # не вариант для этого).

Ответы [ 2 ]

5 голосов
/ 16 марта 2009

То, что вы пытаетесь сделать, не может быть достигнуто с помощью ParamArray. При вызове метода ParamArray происходит следующее:

  1. CLR выделяет массив соответствующей длины
  2. Значения затем копируются в массив
  3. Массив передается в функцию

Нет операции после вызова, которая скопировала бы значения обратно из массива в исходные переменные, которые были переданы.

Единственный надежный способ заставить функцию изменить значение и увидеть ее на сайте вызова - это передать значение ByRef. Вы можете сделать немного магии, чтобы получить набор перегрузок, которые принимают ByRefs, вручную конвертируют в массив и затем копируют обратно. Но это самое близкое, что вы получите.

0 голосов
/ 21 августа 2018

Может быть, немного опоздал для данного случая (почти 10 лет назад), но может помочь кому-то еще, если это работает ...

Вы не можете передать массив параметров как ссылку, но вы можете передать массив как ссылку.

Измените его на ByRef и remove ParamArray

Затем измените эту строку:

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

Просто обратите внимание на дополнительные "{" и "}", чтобы передавать строки как Array, а не как ParamArray

Я использовал это в классе для передачи массива элементов управления, и это сработало (где ParamArray этого не сделал), поэтому я надеюсь (не могу проверить это здесь), но это может стоить попытки

...