Есть ли способ обработать значения 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, разве это не должно сделать только копию указателя и позволить мне изменить базовое значение?
Есть ли лучший способ получить то, что я хочу? (C# не вариант для этого).
2 ответа
То, что вы пытаетесь сделать, не может быть достигнуто с помощью ParamArray. При вызове метода ParamArray происходит следующее:
- CLR выделяет массив соответствующей длины
- Значения затем копируются в массив
- Массив передается в функцию
Не существует операции после вызова, которая будет копировать значения обратно из массива в исходные переменные, которые были переданы.
Единственный надежный способ заставить функцию изменить значение и увидеть ее на сайте вызова - это передать значение ByRef. Вы можете сделать немного магии, чтобы получить набор перегрузок, которые принимают ByRefs, вручную конвертируют в массив и затем копируют обратно. Но это самое близкое, что вы получите.
Может быть, немного опоздал в данном случае (почти 10 лет назад), но может помочь кому-то еще, если это работает...
Вы не можете передать массив параметров как ссылку, но вы можете передать массив как ссылку.
Измените его на ByRef и удалите ParamArray
Затем измените эту строку:
Console.WriteLine("Extension method return value = {0}", str1.SetEqual({str2, str3, str4}))
Просто обратите внимание на дополнительные "{" и "}", чтобы передать строки как Array, а не ParamArray
Я использовал это в классе, чтобы передать массив элементов управления, и это сработало (где ParamArray не сделал), поэтому я надеюсь (не могу проверить это здесь), но это может стоить того