Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / Получить массив из класса по ссылке / 20 сообщений из 20, страница 1 из 1
18.08.2009, 22:09
    #36151141
YUBA
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
Имеется некий класс cData , задача которого подготовка данных для обработки и хранения результирующих данных для последующей обработки. Все делается в Ексел VBA. Вот класс CData (модуль класса)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Dim SD() as UserType
Dim In() as Double
Dim Out as Double
Dim Sigma() as double
'..............................
' Ох, как бы было здорово объявить эти массивы Public, 
' и все проблемы отпали-бы сами собой. :)
'..............................
' Методы класса
'.............................

Дальше не легче.
В программе объявляется массив -
Код: plaintext
Dim DBData() as cData
И самое интересное имеются некие методы работы с массивами, которые требуют ссылки на массив, типа
Код: plaintext
sub ArrJob(Arr() as UserType, ArrJob2() as Double, ...)
И эти методы еще с этими массивами и Redim делают. И переписывать полпрограммы, чтобы они с этими классами работали я не буду ни при каких обстоятельствах. :) А готовить для них копии массивов из класса и после запихивать их обратно, согласитесь, - иначе как дурдомом не назовешь.
Вопрос такой, как из класса получить ссылку на его массив?


"Есть многое на свете, друг Горацио, что и не сразу в голову придет."
М. Твен "Приключения Геккельбери Финна"
...
Рейтинг: 0 / 0
19.08.2009, 13:18
    #36152088
Бенедикт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
YUBA,
технически можно получить ссылку, но идеологически присутствует кричащее противоречие: массив-член класса по каким-то неведомым причинам нельзя объявлять Public, но тут же требуется именно полный доступ извне экземпляра класса. Более-менее красивым выходом здесь видится введение в класс методов-оболочек процедур работы с массивами, т. е.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
Dim SD() as UserType
Dim In() as Double
Dim Out as Double
Dim Sigma() as Double
'..............................
' Методы класса
'.............................
Public Sub ArrJobWrapper(...)
 Call ArrJob(SD() as UserType, Sigma() as Double, ...)
End Sub
...
Рейтинг: 0 / 0
19.08.2009, 14:57
    #36152430
YUBA
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
БенедиктYUBA,
технически можно получить ссылку, но идеологически присутствует кричащее противоречие: массив-член класса по каким-то неведомым причинам нельзя объявлять Public, но тут же требуется именно полный доступ извне экземпляра класса. Бенедикт , это не я придумал.Неведомые причины - это Microsoft, который не разрешает объявлять массивы и usertypы Public. В VB не помню, а в VBA это так. :(
...
Рейтинг: 0 / 0
19.08.2009, 15:05
    #36152460
Konst_One
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
да что вы говорите. пишите свой класс
...
Рейтинг: 0 / 0
19.08.2009, 15:43
    #36152591
YUBA
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
Konst_Oneда что вы говорите. пишите свой класс Если сомневаетесь, в модуле класса, скажем Ексел, напишите - Public Arr() as ..... И посмотрите, что получится. :)
...
Рейтинг: 0 / 0
19.08.2009, 15:49
    #36152612
Konst_One
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
Constants, fixed-length strings, arrays, user-defined types, and Declare statements not allowed as Public members of an object module

Not all variables in an object module can be declared as Public. However, procedures are Public by default, and Property procedures can be used to simulate variables syntactically. This error has the following causes and solutions:


You declared a Public constant in an object module.
Although you can't declare a Public constant in an object module, you can create a Property Get procedure with the same name. If you don't create a Property Let or Property Set procedure with that name, you are in effect creating a read-only property that can be used the same way you would use a constant.

You declared a Public fixed-length string in an object module.
You can simulate fixed-length strings with a set of Property procedures that either truncate the string data when it exceeds the permitted length, or notify the user that the length has been exceeded.

You declared a Public array in an object module.
Although a procedure can't return an array, it can return a Variant that contains an array. To simulate a Public array in a class module, use a set of Property procedures that accept and return a Variant containing an array.

You placed a Declare statement in an object module.
Declare statements are implicitly public. Precede the Declare statement with the Private keyword.


For additional information, select the item in question and press F1 (in Windows) or HELP (on the Macintosh).
...
Рейтинг: 0 / 0
19.08.2009, 16:02
    #36152659
YUBA
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
БенедиктYUBA,
Более-менее красивым выходом здесь видится введение в класс методов-оболочек процедур работы с массивами, т. е.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
Dim SD() as UserType
Dim In() as Double
Dim Out as Double
Dim Sigma() as Double
'..............................
' Методы класса
'.............................
Public Sub ArrJobWrapper(...)
 Call ArrJob(SD() as UserType, Sigma() as Double, ...)
End Sub
Если-бы прога работала с одним классом или по очереди - тогда да, понятно. Но программа должна работать со всем массивом DBData() as cData экземпляров классов сразу, и здесь я уже не могу себе представить как организовать методы-оболочки. По крайней мере без радикального изменения программы обработки.
Нашел вот VarPtr(Arr()) , но пока есть сомнения, особенно в части ReDim.
...
Рейтинг: 0 / 0
19.08.2009, 16:08
    #36152678
Konst_One
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
так всё-таки, почему вы не хотите заменить свои udt-структуры на классы и использовать коллекции вместо массивов?
...
Рейтинг: 0 / 0
19.08.2009, 16:13
    #36152688
YUBA
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
Konst_One,
Симуляция массива передает копию, а не сам массив, а обратно будет опять таки копировать целиком. Это мне не надо, что уже написал в первом посте.
Если учесть, что массивов там где-то на 250-300 МБ, то только копий не хватает для полного счастья.
...
Рейтинг: 0 / 0
19.08.2009, 16:14
    #36152694
Konst_One
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
что-то странное вы задумали на 300Гб в экселе обрабатывать. может стоит трудоёмкие операции вынести в dll , написанную на нормальном языке?
...
Рейтинг: 0 / 0
19.08.2009, 16:15
    #36152696
Konst_One
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
PS
Мб , очепятался
...
Рейтинг: 0 / 0
19.08.2009, 16:22
    #36152729
Бенедикт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
YUBA Бенедикт , это не я придумал.Неведомые причины - это Microsoft, который не разрешает объявлять массивы и usertypы Public. В VB не помню, а в VBA это так. :(Тьфу, едрён батон... :( Помнил про ограничения на константы, UDT и Declare, но почему-то считал, что ограничение не действует на массивы базовых типов. Надо подумать, почему так сделано.

Справка предлагает HelpAlthough a procedure can't return an array, it can return a Variant that contains an array. To simulate a Public array in a class module, use a set of Property procedures that accept and return a Variant containing an array., но это тоже создание копии массива.

Покажу, какую техническую возможность я имел ввиду.
Класс CData:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
Option Explicit

Private Declare Sub CopyMemArrArr Lib "kernel32" Alias "RtlMoveMemory" ( _
   Destination() As Any, Source() As Any, ByVal Length As Long)

Private m_Data() As Long

Public Sub InitData(ByVal nUBound As Long)
 Dim i As Long
 ReDim m_Data( 0  To nUBound) As Long
 For i =  0  To nUBound
    m_Data(i) = i
 Next i
End Sub

Public Sub PrintData()
 Dim i As Long
 If (Not m_Data) <> - 1 & Then
    For i = LBound(m_Data) To UBound(m_Data)
       Debug.Print i, m_Data(i)
    Next i
 End If
End Sub

Public Function GetDataRef() As Long()
 CopyMemArrArr GetDataRef, m_Data,  4 
End Function
Проверочный модуль:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
Option Explicit

Private Declare Sub CopyMemArrAny Lib "kernel32" Alias "RtlMoveMemory" ( _
   Destination() As Any, Source As Any, ByVal Length As Long)

Public Sub Test()
 Dim d As CData
 Set d = New CData
 d.InitData  5 
 d.PrintData
 
 Dim a() As Long
 a = d.GetDataRef 'Получить ссылку на массив
 ProcessArray a   'Обработать массив
 d.PrintData      'Убедиться, что изменения затронули объект
 
 CopyMemArrAny a,  0 &,  4  'Обязательно очистить ссылку на массив!
End Sub

Private Sub ProcessArray(x() As Long)
 Dim i As Long
 ReDim Preserve x(LBound(x) To UBound(x) +  10 ) As Long
 For i = LBound(x) To UBound(x)
    x(i) =  100 & + i
 Next i
End Sub
...
Рейтинг: 0 / 0
19.08.2009, 17:47
    #36153035
YUBA
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
Бенедикт,
Спасибо, попробую вечером.
Еще вопрос, а как определить размер ссылки на Usertype для sub CopyMemArrAny a, 0&, 4 ?
...
Рейтинг: 0 / 0
19.08.2009, 18:20
    #36153124
Бенедикт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
YUBA,
размер ссылки не зависит от размера элемента.

Немного почистил код.
Класс:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
Option Explicit

Private Declare Sub CopyMemArrArr Lib "kernel32" Alias "RtlMoveMemory" ( _
   Destination() As Any, Source() As Any, ByVal Length As Long)
Private Declare Sub CopyMemArrAny Lib "kernel32" Alias "RtlMoveMemory" ( _
   Destination() As Any, Source As Any, ByVal Length As Long)

Private m_Data() As Long

Public Sub InitData(ByVal nUBound As Long)
 Dim i As Long
 ReDim m_Data( 0  To nUBound) As Long
 For i =  0  To nUBound
    m_Data(i) = i
 Next i
End Sub

Public Sub PrintData()
 Dim i As Long
 If (Not m_Data) <> - 1 & Then
    For i = LBound(m_Data) To UBound(m_Data)
       Debug.Print i, m_Data(i)
    Next i
 End If
End Sub

Public Sub GetDataRef(Ref() As Long)
 CopyMemArrArr Ref, m_Data,  4 
End Sub

Public Sub ClrDataRef(Ref() As Long)
 CopyMemArrAny Ref,  0 &,  4 
End Sub
Модуль:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
Option Explicit

Private Sub ProcessArray(x() As Long)
 Dim i As Long
 ReDim Preserve x(LBound(x) To UBound(x) +  10 ) As Long
 For i = LBound(x) To UBound(x)
    x(i) =  100 & + i
 Next i
End Sub

Public Sub Test()
 Dim d As CData
 Set d = New CData
 d.InitData  5 
 d.PrintData
 
 Dim a() As Long
 d.GetDataRef a 'Получить ссылку на массив
 ProcessArray a 'Обработать массив
 d.PrintData    'Убедиться, что изменения затронули объект
 d.ClrDataRef a 'Обязательно очистить ссылку на массив!
End Sub
...
Рейтинг: 0 / 0
19.08.2009, 22:35
    #36153437
YUBA
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
Konst_Oneчто-то странное вы задумали на 300Гб в экселе обрабатывать. может стоит трудоёмкие операции вынести в dll , написанную на нормальном языке? Проект не имеет окончания и будет изменяться пока в нем, проекте и рассчетах, есть необходимость. Т.е функциональность постоянно меняется. Потому и Ексел. И что-то выносить в ДЛЛ просто нет смысла.
...
Рейтинг: 0 / 0
19.08.2009, 23:34
    #36153500
YUBA
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
Бенедикт,
В коде разобрался, спасибо большое. Но что-то конкретное делать пока не начал.
Который год с kernel32 собираюсь разобраться. :(
x(i) = 100& + i Вот не знал, что так преобразование типов можно делать, я бы CLng так и писал. :) В хелпе этого не нашел, но принцип и так понятен.
...
Рейтинг: 0 / 0
25.08.2009, 15:49
    #36162102
YUBA
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
БенедиктYUBA,
технически можно получить ссылку,..... Более-менее красивым выходом здесь видится введение в класс методов-оболочек процедур работы с массивами, т. е.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
Dim SD() as UserType
Dim In() as Double
Dim Out() as Double
Dim Sigma() as Double
'..............................
' Методы класса
'.............................
Public Sub ArrJobWrapper(...)
 Call ArrJob(SD() as UserType, Sigma() as Double, ...)
End Sub
Для решения многих вопросов в этой задаче (не всех) и этого было-бы достаточно.
Казалось-бы. :) Но не тут-то было. Это решение не работает - не идет массив по ссылке даже так.
Идет только вот так.
Объявляем некий Class2 и в него пишем процедуру
Код: plaintext
1.
2.
3.
Public sub ArrJob(SD() as UserType, Sigma() as Double, ...)
..........
end sub
А в классе, где расположены массивы пишем
Код: plaintext
1.
2.
3.
4.
5.
Public Sub ArrJobWrapper(...)
dim a as Class2
set a = new Class2 
Call a.ArrJob(SD, Sigma, Out,...)
set a = nothing
End Sub
Т.е. доступ по ссылке к массивам возможен только к функциям класса объявляемого в "родительском" (не знаю как его назвать правильно).
В общем, пришлось многие функции по импорту данных в массивы класса переделывать в классы и уже оттуда вызывать их функции. Иначе никак. Дурдом.
В общем, идея использовать классы в качестве контейнера для хранения и промежуточной обработки данных и поставщика данных для анализа видимо не так уж и удачна, как казалось.
...
Рейтинг: 0 / 0
25.08.2009, 18:28
    #36162530
Бенедикт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
YUBA Для решения многих вопросов в этой задаче (не всех) и этого было-бы достаточно.
Казалось-бы. :) Но не тут-то было. Это решение не работает - не идет массив по ссылке даже так.Несколько неожиданное суждение.
Пусть есть общий модуль (не модуль класса) с расчётными функциями:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
Option Explicit

Public Type UserType
   Index As Long
   Value As Double
End Type

Public Sub ArrJob(SD() As UserType, Sigma() As Double, ByVal nLen As Long)
 Dim i As Long
 ReDim SD( 0  To nLen -  1 ) As UserType
 ReDim Sigma( 0  To nLen -  1 ) As Double
 For i =  0  To nLen -  1 
    SD(i).Index = i
    SD(i).Value = - 1 # - i *  0 . 001 
    Sigma(i) =  3 # +  10 # ^ (-i -  1 )
 Next i
End Sub
Пусть есть модуль класса CData:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
Option Explicit

Private m_SD() As UserType
Private m_Sigma() As Double

Public Sub InitData(ByVal nLen As Long)
 ReDim m_SD( 0  To nLen -  1 ) As UserType
 ReDim m_Sigma( 0  To nLen -  1 ) As Double
End Sub

Public Sub PrintData()
 Dim i As Long
 If (Not m_SD) <> - 1 & Then
    For i = LBound(m_SD) To UBound(m_SD)
       Debug.Print "SD", i, m_SD(i).Index, m_SD(i).Value
    Next i
 End If
 If (Not m_Sigma) <> - 1 & Then
    For i = LBound(m_Sigma) To UBound(m_Sigma)
       Debug.Print "Sigma", i, m_Sigma(i)
    Next i
 End If
End Sub

Public Sub ArrJobWrapper(ByVal nLen As Long)
 ArrJob m_SD, m_Sigma, nLen
End Sub
Ну и тестовая процедура
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
Public Sub Test()
 Dim c As CData
 Set c = New CData
 c.InitData  3 
 c.PrintData
 Debug.Print "------"
 c.ArrJobWrapper  5 
 c.PrintData
End Sub
Выхлоп в окне Immediate такой:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
Test
SD              0               0               0  
SD              1               0               0  
SD              2               0               0  
Sigma           0               0  
Sigma           1               0  
Sigma           2               0  
------
SD              0               0             - 1  
SD              1               1             - 1 , 001  
SD              2               2             - 1 , 002  
SD              3               3             - 1 , 003  
SD              4               4             - 1 , 004  
Sigma           0               3 , 1  
Sigma           1               3 , 01  
Sigma           2               3 , 001  
Sigma           3               3 , 0001  
Sigma           4               3 , 00001  
Риторический вопрос: почему изменилось количество элементов массивов и их значения?

Давайте пока с этим небольшим вопросом разберёмся.
...
Рейтинг: 0 / 0
25.08.2009, 23:51
    #36162829
YUBA
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
БенедиктНесколько неожиданное суждение.
Пусть есть общий модуль (не модуль класса) с расчётными функциями:
...................................
Риторический вопрос: почему изменилось количество элементов массивов и их значения?
Давайте пока с этим небольшим вопросом разберёмся. Бенедикт , как и следовало ожидать, Ваш код работает. Я должен признать, что был неправ в своем утверждении.

Однако, мне совершенно непонятно, почему мой, практически аналогичный код не работал
1. Имена переменных в вызове процедуры и модуле класса были разные (в моем топике просто иллюстрация). С этой стороны конфликта быть не может. Процедура вызывалась как ModulName.SubName(...), а код не новый. Ошибка была - аргумент не м.б передан By Ref.
2. Class2 получался из модуля тупым копированием содержания в модуль класса, и вставлением в вызов функции
Код: plaintext
1.
2.
dim a as Class2
set a = new Class2 
Call a. ...........
и все начинало функционировать.
Вернуть все обратно в том-же виде уже вряд-ли возможно, но попытаюсь смоделировать. Уже просто интересно в чем-же дело было. Сделаю -отпишусь.
...
Рейтинг: 0 / 0
27.08.2009, 13:13
    #36166011
YUBA
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Получить массив из класса по ссылке
Заставить не работать конструкцию так и не удалось.
Теперь о применении всего этого в реальной программе и как это выглядит. М.б. кому пригодится.
1. Создаем некий базовый класс сDate в модуле класса
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
Dim SD() as UserType
Dim In() as Double
Dim Out() as Double
Dim Sigma() as double
'--------------------------
'Методы базового класса
..................................
'---------------------------
'Методы - интерфейсы вида
Sub F1(Param1 as ...., .......,ParamN as .....)
'Здесь пусто. в дальнейшем сюда помещаются методы-интерфейсы из просто модуля
End Sub
'...................
Теперь этот класс можно размножать простым копированием.
Создаем модуль интерфейсов mInterface с интерфейсными методами
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
 'Интерфейсы для функций F1 ...... FN класса cData
Sub iF1_1(mSD as UserType,mIn as Double, mParam1 as ,......)
End Sub
Sub iF1_2(mSD() as UserType, mIn() as Double, ..., mParam1 as ,......)
End Sub
'.......
Sub iF1_N(mSD() as UserType, mIn() as Double, ..., mParam1 as ,......)
'.......
End Sub
'.................
Теперь осталось клонировать модули класса с заменой имени, подставить в каждый класс свои интерфейсы. Далее запихиваем классы в массив вида Dim cD() as Object. Далее, т.к. все вызовы базовых поцедур и интерфейсов стандартизованы можно проводить инициализацию классов и обработку данных в цикле по списку параметров.
Далее создаем и отдаем указатели на массивы данных на последующую обработку.
Ну вот что получилось из этой темы :)
Всем спасибо.



"Есть многое на свете, друг Горацио, что и не сразу в голову придет."
М. Твен "Приключения Геккельбери Финна"
...
Рейтинг: 0 / 0
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / Получить массив из класса по ссылке / 20 сообщений из 20, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]