Мир объектов Excel 2000

Смотри здесь томатис оборудование. |

"Пользовательские" и "обычные" функции VBA


Под пользовательской функцией VBA я понимаю функцию, которая может быть вызвана в формулах рабочего листа Excel. Обычные функции VBA могут вызываться в функциях и процедурах VBA. Возникает естественный вопрос, может ли одна и та же функция одновременно быть пользовательской и обычной? Этот же вопрос может быть сформулирован и по-другому, есть ли особая специфика в пользовательских функциях? Ответ прост - особой специфики нет, и одна и та же функция может вызываться как в формулах, так и в процедурах VBA. Практически не возникает проблем, когда аргументами функции и результатом являются скалярные значения. Когда же, как в случае с MultMatr, аргументами и результатом являются массивы, то возникают определенные трудности. Эти трудности преодолимы, примером тому служит функция MultMatr. Попробуем разобраться, в чем состоят эти трудности. Когда функции нужно предать массив, то в пользовательских функциях при вызове им передаются объекты Range, обычным функциям - пер еменные, описанные, как массивы VBA. Поэтому для обеспечения универсального характера функции в ее теле необходимо производить разбор случаев, определяя тип параметра. В результате растет объем функции, а, следовательно, усложняется ее понимание. Еще одна сложность связана с результатом вычислений. Никаких проблем нет для формулы над массивами, вызывающей пользовательскую функцию, - результат, записывается в область, выделенную при вызове формулы. Обычные функции VBA, как правило, не возвращают массив в качестве результата. Если результатом работы является массив, то при программировании на VBA создается процедура, а не функция. Дело в том, что в VBA присваивания над массивами запрещены, потому просто невозможно присвоить массиву значение обычной функции, возвращающей массив в качестве своего результата. Как же, спросите Вы, MultMatr может использоваться в качестве обычной функции? Только за счет маленьких хитростей и универсального типа Variant, который может быть чем угодно, в том числе и массивом. При вызове MultMatr как обычной функции в процедуре VBA результат вызова присваивается переменной типа Variant, - это допустимо. Затем уже с этой переменной можно работать как с массивом, - это тоже допустимо, что я и продемонстрирую чуть позже. Таким образом, всегда можно написать функцию так, чтобы она служила и как пользовательская и как обычная функция. Другой вопрос, стоит ли это делать. В таком обобщении есть свой резон, поскольку в таких случаях при вызове пользовательской функции ей можно передавать в качестве аргументов не только объекты Range, но и массивы констант, что было продемонстрировано при рассмотрении функции IsMedianaForAll. Заметьте, однако, что в функцию MultMatr передать массивы констант невозможно. Причина этого в том, что для двумерных массивов констант функции UBound и LBound работают некорректно.

Подводя итог, замечу, что, когда приходится работать с массивами, разумнее иметь два варианта - пользовательскую и обычную функцию. Чтобы отчетливее продемонстрировать разницу между обычными и пользовательскими функциями, я написал обычную процедуру MultMatr1, выполняющую умножение матриц. Вот ее текст:

Public Sub MultMatr1(A() As Variant, B() As Variant, C() As Variant) 'Умножение матриц. 'Процедуру можно вызывать в обычных VBA функциях и процедурах, 'передавая ей в качестве параметров массивы VBA. Dim i As Integer, j As Integer, k As Integer Dim N As Integer, M As Integer, Q As Integer Dim P As Integer, NC As Integer, PC As Integer Dim msg1 As String, msg2 As String Dim Uncor1 As Boolean, Uncor2 As Boolean Dim Elem As Variant Uncor1 = True: Uncor2 = True msg1 = " При вызове MultMatr некорректно задана размерность" _ & " перемножаемых матриц!" & vbCrLf & _ "Число столбцов матрицы A = " & M & vbCrLf & _ "Число строк матрицы B = " & Q msg2 = " При вызове MultMatr некорректно задана размерность" _ & " матрицы результата!" & vbCrLf & _ "Число строк матрицы C = " & NC & vbCrLf & _ "Число столбцов матрицы C = " & PC




Начало  Назад  Вперед



Книжный магазин