neděle 19. července 2009

Reflexe - vytvoření objektu, volání metod

Původně jsem se chtěl vrátit k Team Foundation Serveru, ale času se nějak nedostává a plány se odsouvají... Takže raději zpátky k tématu reflexe. V poslední době jsem níže uvedené informace vyvsvětloval postupně několika lidem, tak bude asi vhodné to sepsat. Podívejme se na případ, kdy máme jméno (nebo ID) třídy a chceme vytvořit instanci.
ClassName className = 'SalesFormLetter_Invoice';
SysDictClass dictClass = new SysDictClass(className2Id(className));
FormLetter formLetter;
;
formLetter = dictClass.makeObject(true);
Jméno jsem převedl na ID, vytvořil instanci SysDictClass a zavolal metodu makeObject(). Té lze předat parametry, které očekává konstruktor. Je zajímavé, že nedojde k run-time chybě ani když vynechám povinný parametr (AX přiřadí parametru default hodnotu). Vtipně provádí validaci SysDictClass.allowMakeObject(). :-) Teď můžeme zavolat metodu objektu FormLetter. Na tom nic není. Ale co když neznám typ objektu? Mohu například zjistit, zda třída implementuje nějaké rozhraní a přetypovat na něj.
if (dictClass.isImplementing(classNum(SysRunable)))
{
   sysRunable = dictClass.makeObject();
   sysRunable.run();
}
Obdobně zjistím, zda je potomkem nějaké třídy.
if (dictClass.isExtending(classNum(RunBaseBatch)))
Nebo prostě zkusím, zda má objekt nějakou konkrétní metodu:
IdentifierName methodName = 'xml';
SysDictClass dictClass = new SysDictClass(classNum(Query));
Object object;
;

object = dictClass.makeObject();

if (dictClass.hasObjectMethod(methodName))
{
   info(dictClass.callObject(methodName, object, 10));
}
Metoda callObject() tedy očekává název metody, instanci objektu, jehož metoda se má volat, a případné parametry metody. Obdobně lze volat i statické metody. Jedno z možných použití je samozřejmě i vytvoření instance:
SysDictClass dictClass = new SysDictClass(classNum(InventItemType));
Object object;
;
object = dictClass.callStatic('construct', ItemType::Service);
U tabulek je to pak velmi podobné, jen místo makeObject() se použije makeRecord():
SysDictTable dictTable = new SysDictTable(tableNum(LedgerJournalTrans));
Common common;
;
common = dictTable.makeRecord();
dictTable.callObject('initFromCustTable', common, CustTable::find('1'));
U tabulek nás ale většinou zajímá jestě jedna věc a tou věcí jsou datová pole. Tam přijde ke slovu trochu neobvyklá syntaxe tabulka.(číslo pole). Například:
InventTable inventTable = InventTable::find('1');
SalesLine   salesLine = SalesLine::findInventTransId('12345', true);
Common      table1 = inventTable;
Common      table2 = salesLine;
FieldId     fieldId1 = fieldNum(InventTable, ItemId);
FieldId     fieldId2 = fieldNum(SalesLine, ItemId);
;
table1.(fieldId1) = table2.(fieldId2);
Poslední příklad ukazuje, jak získat hodnotu na základě jména pole:
SysDictTable dictTable;
Common common;
FieldId fieldId;
;
dictTable = new SysDictTable(common.TableId);
fieldId = dictTable.fieldName2Id('Name');
if (fieldId)
{
   info(common.(fieldId));
}
Užitečný odkaz: MSDN: Intrinsic Functions

Žádné komentáře:

Okomentovat