čtvrtek 25. listopadu 2010

Tabulky v Table map

Řekněme, že píšete třídu, která bude schopná pracovat s libovolnou tabulkou z určité mapy (třeba PBAItemLine, v mém případě). V objektu typu Args vám přijde buffer, a vy byste rádi zkontrolovali, zda patří mezi tabulky definované v dané mapě.

K tomu lze využít metodu SysDictTable::isTableMapped(); konkrétní přiklad by vypadal takto:

if (SysDictTable::isTableMapped(tableNum(PBAItemLine), _args.dataset()))

Implementace metody isTableMapped() je trochu ošklivá (dívá se přímo do AOT na obsah uzlu Mappings),  inteligentní podpora zřejmě v API chybí.

Mimochodem, instance třídy DictTable může reprezentovat nejen "klasickou" tabulku, ale i Map nebo View.

pondělí 15. listopadu 2010

Implementace metod definovaných rozhraním

Při přípravě jiného článku jsem narazil na dost… osobité chování Axapty při implementaci rozhraní. Navzdory veškerým očekáváním Axapta nekontroluje, zda má implementující třída správné veřejné rozhraní (proto interface), ale jen že má metody shodných názvů, jaké má i rozhraní.

Ukažme si to na příkladu. Definuji následující rozhraní:
interface Rozhrani
{
    int rychlost(int _rychlost){}
}
Předpokládal bych, že každá třída implementující toto rozhraní musí obsahovat metodu rychlost() s parametrem a návratovou hodnotou typu int.

Následující třída jde nejen zkompilovat, ale kód v metodě main() i bez chyby proběhne, včetně přiřazení do proměnné.
class ImplementujiciTrida implements Rozhrani
{
    //Správný název metody, ale nesprávný typ parametru i návratové hodnoty
    void rychlost(str _slovniPopisRychlosti)
    {}

    public static void main(Args _args)
    {
        Rozhrani trida = new ImplementujiciTrida();
        //Instance nemá metodu akceptující číselný parameter a vracející hodnotu,
        //přesto toto volání proběhně.
        int i = trida.rychlost(5);
    }
}
Metoda rychlost() obdrží hodnotu překonvertovanou do řetězce a vrátí hodnotu 0 (případná hodnota v proměnné i v main() by byla přepsána), přestože má návratový typ void.
Pokud by implementace metody rychlost() obsahovala parametr, pro který neexistuje implicitní konverze (např. Object _o), dojde k chybě za běhu aplikace.

Rozhraní má poskytnout jistotu, že instance každé implementující třídy "rozumí" určitému způsobu komunikace, tedy že je možné zavolat nějakou metodu s předem danými typy parametrů. Když se třída hlásí k určitému veřejnému rozhraní (= implementuje interface), kompilátor by měl zajistit, že tomu tak skutečně je. Kompilátor Axapty to ale nedělá - a výsledkem chyby, kterou měla odhalit první kompilace, může být runtime exception nebo opravdu nepochopitelné chování aplikace.

Tímto nechci říct, že se v X++ nemají rozhraní používat. Naopak si myslím, že se používají málo (a místo nich se vytváří sporné hierarchie dědičnosti apod.). Ale nelze se spoléhat na kompilátor, že korektní implementaci rozhraní vynutí.