Top.Mail.Ru

Расширения классов в Microsoft Dynamics 365

Для того чтобы не подвергать изменению типовые объекты в Microsoft Dynamics 365 была придумана концептуально новая модель работы с ними – это расширения. Расширения позволяют расширять функциональность объектов в новой модели. В этой статье будет описываться расширения кода X++.

Концепция эффективного класса

Допустим есть класс MyClass у него есть переменная field1 и метод myMethod. В нашей новой модели мы хотим расширить функциональность класса MyClass, для этого создаем новый класс MyClass_Extension и добавляем в него переменную field2 и метод myMethod1. В нашей модели эффективным классом будет являться класс MyClass с переменными field1 и field2 и методами myMethod и myMethod1. Расширенная функциональность эффективного класса MyClass не будет доступна для других моделей, поскольку расширенная функциональность определена только в нашей модели.

Создание класса расширения

Класс расширения помечается атрибутом ExtensionOf, где указывается класс, в котором будем расширять функциональность, и суффиксом _Extension (в будущем суффикс _Extension может стать необязательным). От класса расширения нельзя наследоваться поэтому его нужно помечать модификатором final. Для одного класса можно создать несколько классов расширения в одной модели.

Пример создания класса расширения

[ExtensionOf(classStr(MyClass))]
final class MyClass_Extension
{
    ...
}

Наследование эффективного класса

Любой класс можно наследовать от эффективного класса. Все методы и переменные из классов расширений будут также унаследованы в новый класс.

Конструкторы классов расширения

Конструктор экземпляра (метод new) объявленный в классе расширения не может иметь параметры и не может быть вызван в коде поэтому он помечается модификатором private. Конструктор нужен для инициализации объектов класса расширения. Статический конструктор (метод typeNew) так же может быть объявлен в классе расширения.

Методы

Методы, помеченные модификатором public будут доступны из эффективного класса, соответственно методы, помеченные модификатором private не будут доступны из эффективного класса. Поскольку класс расширения является финальным то методы нельзя помечать модификатором protected.

Пример создания метода в классе расширения

[ExtensionOf(classStr(MyClass))]
final class MyClass_Extension
{
    private void new()
    {
    }

    public int ExtensionMethod(int arg)
    {
	info(int2str(arg));
	return arg;
    }
}

Метод ExtensionMethod объявленный в классе расширения теперь доступен из эффективного класса

Пример использования метода ExtensionMethod из эффективного класса

MyClass myClass = new MyClass();
myClass.ExtensionMethod(16);

По аналогии с методами экземпляра можно добавлять и статические методы в класс расширения, и они также будут доступны из эффективного класса.

Пример создания статического метода

[ExtensionOf(classStr(MyClass))]
final class MyClass_Extension
{
    private void new()
    {
    }

    public static int ExtensionStaticMethod(int arg)
    {
        return arg * arg;
    }
}

Пример использования статического метода

int value = MyClass:: ExtensionStaticMethod(25);

Переменные

Работа с переменными осуществляется по аналогии с методами.

Пример создания переменных

[ExtensionOf(classStr(MyClass))]
final class MyClass_Extension
{
    public int field1;
    public static int staticField1; 
    private void new()
    {
    }
    static void TypeNew()
    {
        staticField1= 55;
    }
}

Пример использования переменных в коде

MyClass c = new MyClass();
c.field1 = MyClass::staticField1;

Обертывание методов

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

Пример обертывания метода

class MyClass
{
    public void proc()
    {
        info(“proc”);
    }
}

[ExtensionOf(ClassStr(MyClass))]
final class MyClass_Extension
{
    public void proc()
    {
        next proc();
        info(“proc extension”);
    }
}

MyClass myClass = new MyClass();
myClass.proc();

В результате получим два сообщения proc и proc extension.

В методе обертке в классе расширения используется вызов next, он нужен чтобы выполнить код в методе proc в эффективном классе. Более подробно о next будет описано ниже.

Обертывать можно только методы, помеченные модификаторами public и protected. Нельзя обернуть метод если он был создан не в эффективном классе, т.е. если создано несколько классов расширения для одного класса (эффективный класс), то обернуть можно только методы эффективного класса. Можно обернуть как методы экземпляра, так и статические методы.

В случае если обертываемый метод содержит входные переменные со значениями по умолчанию, то в классе расширения этот метод не будет содержать значения по умолчанию.

Пример обертывания метода с входными параметрами со значениями по умолчанию

class MyClass
{
    public void proc(int value = 100)
    { 
        ...
    }
}

[ExtensionOf(classtr(MyClass))]
final class MyClass_Extension
{
    public void proc(int value)
    { 
        ...
    }
}

Вызов next

В классе расширения методы, которые обертываем, должны содержать вызов next. Это делается для того чтобы гарантировать получение результата при выполнении метода.

Есть правила использования next:

next не может вызываться внутри оператора if

next не может вызываться внутри циклов

next не может вызываться после return

— нельзя вызывать next внутри логических выражений

Это все хорошо если нам нужно добавить новое условие или какую-нибудь независимую обработку вначале или в конце метода, а что, если нужно перепилить функционал полностью или навтыкать кучу условий, зависимых от уже имеющихся или добавить обработку внутри транзакции. В этом случае нам поможет атрибут [Replaceable]. Этот атрибут нужно устанавливать в начале обертываемого метода. В методе, помеченном данным атрибутом вызывать next не нужно.

Атрибут Wrappable

Методы, помеченные модификатором final не могут быть обернуты в классах расширения, но если этот метод пометить атрибутом Wrappable со значение true, то такой метод можно будет обернуть. В случае если нужно наоборот закрыть возможность обертки метода, то нужно пометить этим же атрибутом, но со значением false.

Пример использования атрибута Wrappable

class MyClass 
{
    [Wrappable(false)]
    public void proc(int rate)
    {
        ...
    }

    [Wrappable(true)]
    final public void procFinal(int rate)
    { 
        ...
    }
}

Ограничения на обертывание методов

Классы ядра не являются классами X++, поэтому методы этих классов нельзя обернуть, но при этом эти классы можно расширять.

Класс формы расширить можно, а вот классы, используемые для элементов или источников данных принадлежащих форме расширить нельзя и соответственно методы обернуть не получится.

Comments

So empty here ... leave a comment!

Добавить комментарий

Sidebar