Страницы: 1
RSS
отличие пользовательских классов от встроенных
 
Подскажите, верно ли утверждение, что одно из существенных отличий пользовательских классов от встроенных классов (листы, рабочие книги, имена диапазонов и пр) заключается в том, что первые теряют данные объектов при закрытии файла, а вторые нет???!!!  
 
Если это ни так, то как можно создать объекты пользовательского класса, чтобы данные об объекте сохранились при повторном открытии файла?
 
В Excel листы и книги являются экземплярами встроенных классов, а имена диапазонов не являются таковыми, они лишь часть либо книги, либо листа.  
 
При сохранении (или закрытии с сохранением) данные и свойства книг и листов, естественно, сохраняются в файле.  
 
Экземпляры пользовательских классов тоже могут сохранять данные, но прицепившись к встроенным (листам или книге). Например, сохранять что-то на скрытых листах или в именах книги/листов, или в свойствах документа книги. Это если нужна привязка к файлу. А если не нужна, то можно сохранять и в реестре.
 
спасибо, я так и думал что нужно цепляться к чему-то, что уже встроено в Эксель (листы, имена и пр.).    
В этом смысле пользовательские классы уступают встроенным, которые сохраняют информацию об объектах.    
 
Об этом вроде бы теперь очевидном факте не говорится непосредственно нигде!
 
> В этом смысле пользовательские классы уступают встроенным  
 
Вовсе нет.  
Просто разработчики встроенных в Excel классов, не поленились создать методы типа Open и SaveAs для некоторых из своих классов (например, для класса Workbook),  
а вам не хочется реализовывать эти методы, вот и жалуетесь на несовершенство классов.  
 
Я вот, например, когда мне нужно сохранять экземпляры классов, добавляю в них указанные 2 метода, и объекты выгружаются в XML, и потом загружаются из него же.  
 
Да, кода много (лишние 20...200 строк), но по-другому я не знаю как.  
 
Кстати, вопрос к Владимиру (ZVI): а есть способ сохранять произвольный экземпляр произвольного класса VBA в бинарном виде, и потом загружать из этого бинарного файла?  
Код не нужен, хотелось бы просто узнать ответ - возможно это теоретически, или нет.  
(например, что-то вроде сохранение в файл участка памяти, где хранится экземпляр класса. Или это уже из уровня фантастики?)
 
спасибо, очень интересно, но тогда еще вопрос.    
 
Можно создать свои методы и свойства для встроенных классов?  
 
Где-то в книге прочел, что вроде можно, но не могу найти где?  
От пользователей форума получал ответ, что нет!  
 
Хочу окончательно прояснить ситуацию!
 
Ко встроенным классам методы и свойства вы не добавите.  
В отличие от других языков программирования, VBA этой возможности не даёт.  
 
Вы же про пользовательские классы спрашивали (которые вы сами создаёте) - вот там можно.
 
{quote}{login=EducatedFool}{date=14.10.2012 02:34}{thema=}{post}Ко встроенным классам методы и свойства вы не добавите.  
В отличие от других языков программирования, VBA этой возможности не даёт.{/post}{/quote}  
но никто Вам не запрещает создать объект обертку, в качестве свойств которой выступают экземпляры встроенных классов (псеводокод):  
 
var wparObj = {  
____collection: New Collection,  
____userMethod: function() {}  
};
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
>>var wparObj = {  
____collection: New Collection,  
____userMethod: function() {}  
};  
Переведу на VBA. В модуле класса wparObj пишем  
Public baseCollection As New Collection  
Public Sub userMethod()  
End Sub  
Соответственно переменная в коде, например модуля  
Dim newColl As New wparObj  
'Для работы с коллекцией  
newColl.baseCollection.Add "newItem", "newKey"  
С методом расширения  
'newColl.userMethod  
Только гуру ООП говорят, что прямой доступ к полю переменной класса не есть хорошо. Мы можем, конечно, переписать все вызовы к Collection в нашем классе, но есть пункт 2.  
Второе, если у нас функция принимает только переменную типа Collection, то мы не можем передать ей wparObj.  
 
евл  
>>Можно создать свои методы и свойства для встроенных классов?  
А можете ли объяснить смысл такой операции? Ведь никакой другой код, кроме написанного вами не поймёт наличие новых методов и свойств. Переопределение же методов в VBA отсутствует (в силу отсутствия механизма наследования), так что и изменить поведение существующих методов будет не возможно.
 
> Переведу на VBA  
спасибо )  
 
> Только гуру ООП говорят, что прямой доступ к полю переменной класса не есть хорошо.  
Что? Вообще-то, для этого и делают свойства Public. То, что должно быть изолировано - Private.  
 
> Мы можем, конечно, переписать все вызовы к Collection в нашем классе, но есть пункт 2.  
не понял. Какой еще п.2? То, о чем говорил я?  
 
> Второе, если у нас функция принимает только переменную типа Collection, то мы не можем передать ей wparObj.  
свойство wparObj.collection передадим. Разумеется, это не так удобно, как зашить свои методы в встроенный класс, но другого простого способа я не вижу.  
 
> А можете ли объяснить смысл такой операции?  
Конечно. Например, у нас есть VBA 100500 в котором у встроенного класса Collection есть метод doSomething (который очень хотелось бы использовать), а в нашем VBA 6/7 этого метода нет. Еще пример: добавить всяких удобняшек, которыми пользуется лично Вася Пупкин.  
 
> в силу отсутствия механизма наследования  
тогда, что такое Implements?
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
ответ для anvg:  
 
Ну например, хочется создать красивые методы для встроенного объекта коллекции Names, и рассматривать среди них только те имена, которые ссылаются на именные диапазоны.    
 
Как пример, ищет в первой строке диапазона нужную ячейку с определенным значением, затем удаляет столбец, содержащий эту ячейку и т.д. и т.д. фантазии могут быть неограниченными....  
 
Поскольку вы меня спросили, то я призадумался......Конечно можно создать свой собственный пользовательский класс также типа диапазона и делать с ним что хочешь.....  
 
 
wparObj - это что-то встроенное в эксель или сами его определили?
 
Зачем так издеваться? Разве не лучше написать несколько универсальных функций?
Киса, я хочу Вас спросить, как художник — художника: Вы рисовать умеете?
 
Шо, о5? ;))   
http://www.planetaexcel.ru/forum.php?thread_id=43428
 
Казанский, кстати, той штукой я по большому счету так и не пользовался : )
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
 
Александр nerv не ершитесь - вашу реализацию Collection видел. Если чем обидел - прошу простить. Мой пост был для ТС, как пояснение того, что ждёт его на этом пути, в силу отсутствия механизма наследования в VBA. Может что и не внятно объяснил, извиняюсь. Мне ли вас учить?  
Как раз, если бы было наследование в VBA, то не нужено было использовать включение. Класс потомок добавил бы свои методы, свойства, а необходимые методы предка переопределил. В этом бы случае мы спокойно бы передавали newCollection, как параметр в функциию.  
Ксати добавление методовЮ свойств, не через создание класса потомка, а существующему классу есть в VB.Net C# начиная с VS2008. Всё же ООП это обстракция над реальным машинным кодом. А всякая абстракция может быть изменена.
 
В книге "Профессиональная разработка приложений Excel" (Стивен Буллен, Роб Боуви, Джон Грин) есть глава 7 "Использование модулей классов для создания объектов".  
Сканирование займёт некоторое время, но если народу нужно, сделаю в течении дня.  
Архив с примерами к этой главе (123 кБ): http://narod.ru/disk/62479891001.162217fff42c5f3a2db695d725dd355e/Ch07%20-%20Using%20Class%20Modules%20to%20Create%20Objects.rar.html
 
{quote}{login=EducatedFool}{date=14.10.2012 12:02}{thema=}{post}Кстати, вопрос к Владимиру (ZVI): а есть способ сохранять произвольный экземпляр произвольного класса VBA в бинарном виде, и потом загружать из этого бинарного файла?  
Код не нужен, хотелось бы просто узнать ответ - возможно это теоретически, или нет.  
(например, что-то вроде сохранение в файл участка памяти, где хранится экземпляр класса. Или это уже из уровня фантастики?){/post}{/quote}  
Привет, Игорь! Отвечаю немного с задержкой - был очень занят.  
Вопрос интересный, и без кода, конечно, же не обойдусь, он приведен ниже.  
 
Сохранить копию объекта класса из дампа heap-памяти, думаю, возможно. Но смысла мало, так как там будут ссылки на адреса данных, которые хранятся в других местах. Потребуется же распарсивать все эти данные и потом куда-то их пристегивать. Например, в переменой сохранено текстовое значение, но на самом деле в переменой хранится только ссылка на другой место памяти, где начинается первый символ текста, а в 4-х байтах перед этим местом в бинарном виде (Long) записано количество символов этого текста.  
 
По-моему, проще хранить необходимые данные внутри private-массива класса и сохранять этот массив в бинарном виде напрямую в файл, а при необходимости - считывать из файла прямо в массив.  
 
Напрашивается, конечно, вопрос: "а разве в массиве не придется парсить ссылки к данным, которые хранятся в других участках памяти, например, к текстовым, как было описано выше?"  
 
Ответ может удивить, но функция Put сделает это сама!  
А Get при считывании из файла рассует данные в памяти должным образом.  
 
Интересно, что при этом считывание из файла может производиться и в массив с другими размерностями (о равенстве общего количества элементов нужно позаботиться самому) - обратите внимание на то, что в примере считывание производится и в массив b().  
 
Вот код для иллюстрации:  
 
Option Explicit  
 
Dim a(1 To 6), b(1 To 2, 1 To 3)  
 
Sub Main()  
 EraseArray  
 FillArray  
 ArrayToFile  
 EraseArray  
 FileToArray  
 CheckArray  
End Sub  
 
 
Sub FillArray()  
 a(1) = 10  
 a(2) = 2.3456789  
 a(3) = "Any text"  
 a(4) = Now  
 a(5) = 123456  
End Sub  
 
' Saving variant array to file  
Sub ArrayToFile()  
 Dim FN%, f$  
 FN = FreeFile  
 f = ThisWorkbook.FullName & ".bin"  
 If Len(Dir(f)) Then Kill f  
 Open ThisWorkbook.FullName & ".bin" For Binary As FN  
 Put #FN, , a  
 Close #FN  
End Sub  
 
' Erasing array  
Sub EraseArray()  
 Erase a()  
End Sub  
 
' Loading binary file into array  
Sub FileToArray()  
 
 Dim FN%, f$  
 
 FN = FreeFile  
 f = ThisWorkbook.FullName & ".bin"  
 If Len(Dir(f)) = 0 Then Exit Sub  
 
 Open f For Binary As FN  
 Get #FN, , a  
 Close #FN  
 
 Open f For Binary As FN  
 Get #FN, , b  ' <-- different size!  
 Close #FN  
 
 'Kill f  
 
End Sub  
 
Sub CheckArray()  
 Dim i&, r&, c&  
 
 Debug.Print "a(1 to 6)", UBound(a)  
 For i = 1 To UBound(a)  
   Debug.Print i, TypeName(a(i)), a(i)  
 Next  
 
 On Error GoTo exit_  
 Debug.Print "b(1 to 2, 1 to 3)", UBound(b, 1), UBound(b, 2)  
 For c = 1 To UBound(b, 2)  
   For r = 1 To UBound(b, 1)  
     Debug.Print r & " " & c, TypeName(b(r, c)), b(r, c)  
   Next  
 Next  
 
exit_:  
 Err.Clear  
 
End Sub  
 
 
Таким же образом можно сохранять/восстанавливать и объекты, например, объект Dictionary. Перед сохранением нужно в 2-мерный массив считать Items и Keys и сохранить массив в файл. А считывать - сначала из файла в массив, а затем - в новый Dictionary
 
Владимир, спасибо огромное!  
Я и не подозревал, что массив можно сохранить в бинарный файл так просто.  
 
Да ещё и размерность при чтении любую получить... получается, таким образом (при помощи пары функций - чтения\записи массива в файл), легко можно произвольно менять размерности массива.  
 
Из ваших сообщений на форуме, каждый раз узнаю что-то новое.  
Ещё раз спасибо!
 
Игорь, да я у Вас тоже многому учусь :-)  
Непринципиально, но для красоты в коде ArrayToFile  лучше  
вместо:  Open ThisWorkbook.FullName & ".bin" For Binary As FN  
записать: Open f For Binary As FN  
А в коде EraseArray дописать еще и Erase b()
Страницы: 1
Читают тему
Наверх