суббота, 16 апреля 2016 г.

Cache': Обращаемся к своему свойству

В методе объекта обратиться к своему свойству можно 4-мя способами. Когда какой предпочтительней и какая между ними разница?
Будем рассматривать примеры обращения к свойству объекта на классе
Class Test.NewClass1 Extends %Persistent
 [ ClassType = persistent]
{

  Property Prop As %String;

  Method Meth()
  {
 w ..Prop
 w ##this.Prop
 w %this.Prop
 w i%Prop
  }

}
и проводить различные к нему добавления для исследования. Исследование поведения можно провести самостоятельно, открыв и просмотрев получающиеся после трансляции коды int-рутин.

Обращение через ..PropName


При трансляции такого обращения компилятор проверяет наличие такого свойства и что транслируется метод объекта, а не класса. Если для этого свойства не было определения property getter или property setter, то транслируется в оптимизированный код прямого доступа к слоту (раннее связывание), иначе код транслируется в код вызова значения через объектный движок (позднее связывание). Что интересно - достаточно объявления геттера без сеттера и наоборот, трансляция все равно приводит к позднему связыванию.

Если обращаемся к свойству в классе наследнике, в котором определяем геттер или сеттер, то при трансляции методов все базовые методы, унаследованные им, автоматически перетранслируются в этом классе и получаем позднее связывание.

Обращение через %this.PropName


Это синтаксис обращения к свойству объекта, на который указывает локальная переменная %this. В ней нет ничего такого особенного, за одним исключением - в методах объектов эта переменная является формальным параметром (первым), автоматически генерируемым при генерации рутин.

При трансляции не проверяется что это за переменная, является ли объектом, какого типа, есть ли у этого типа это свойство, и каков контекст трансляции. Этот факт можно использовать, например, в методах классов или в обычных рутинах, которые вызываются из методов объектов и по переменной %this определить вызывающий объект. Кроме того, отсутствие проверки на существование свойства может быть использовано для обращения к свойствам, которые еще неизвестны - компилятор не будет препятствовать.

Код обращения через %this.PropName всегда транслируется в позднее связывание независимо от наличия геттера и сеттера.

Обращение через ##this.PropName


Судя по поведению транслятора, использование директивы препроцессора ##this полностью аналогично использованию локальной переменной %this. Директива всегда заменяется на %this.

В версии cache постарше, где есть code complete (например, cache 5.2.3), использование директивы ##this позволяет использовать список альтернатив продолжения кода.

Обращение через i%PropName или r%PropName


Обращение к свойству через i%PropName или r%PropName всегда транслируется в код раннего связывания. Примерно такого вида:
$zobjval(,3,0,3,3)
Самостоятельно обращаться к функции $zobjval, мягко говоря, не рекомендуется.

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

Если объект есть свойство datatype класса, то нужно использовать форму i%PropName, если свойство объектное и является ссылкой, то форму r%PropName.

Синтаксически не поддерживается обращение через i%PropName или r%PropName к объекту в указанной программистом локальной переменной.

1 комментарий:

  1. так же возможно обращению к свойству объекта через $this.Property, но работать это будет только в контексте объекта, в коде classmethod в специальной переменной $this уже будет не объект а имя класса. Поэтому использовать $this нужно очень внимательно.

    Если имя свойства у нас в виде строки, то получить значение свойства через функцию $zobjproperty, которая в последствии была заменена на $property(obj, "property"), для методов так же есть функции $method и $classmethod.

    При разработке класса еще есть возможность указать специальный метод, который будет вызываться при обращении к неописанным свойствам класса, это метод %DispatchGetProperty, более подробно в документации (http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GOBJ_dynamicdispatch)

    кстати такой вариант тоже рабочий, но не стоит так делать, только в исключительных случаях, например при работе с JSON
    Property "Some-Property" As %String;

    write .."Some-Property"

    ОтветитьУдалить