Есть ли способ обрабатывать значения ParamArray как byRef, чтобы их можно было обновить?

Звучит достаточно просто, но это не работает. В этом примере я хочу установить значения 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, разве это не должно создавать только копию указателя и позволять мне изменять базовое значение?

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


person StingyJack    schedule 16.03.2009    source источник


Ответы (2)


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

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

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

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

person JaredPar    schedule 16.03.2009
comment
О, Джой. Вот чего я боялся. Спасибо, Джаред. - person StingyJack; 16.03.2009

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

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

Измените его на ByRef и удалите ParamArray.

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

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

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

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

person torpid prey    schedule 21.08.2018