ENTERPRISE

Microsoft Dynamic AX 2009 : Reflection APIs (part 2) - Dictionary API

11/16/2013 2:31:39 AM

2. Dictionary API

The dictionary API is a type-safe reflection API that can reflect on many elements. The following code sample is a revision of the preceding example that finds inventory classes by using the dictionary API. You can’t use this API to get information about when an element was modified. Instead, this example reflects a bit more on the class information and lists only abstract classes.

static void findAbstractInventoryClasses(Args _args)
{
Dictionary dictionary = new Dictionary();
int i;
DictClass dictClass;

for(i=1; i<=dictionary.classCnt(); i++)
{
dictClass = new DictClass(dictionary.classCnt2Id(i));

if (dictClass.isAbstract() &&
strStartsWith(dictClass.name(), 'Invent'))
{
info(strfmt("%1", dictClass.name()));
}
}
}


The Dictionary class provides information about which elements exist. With this information, you can instantiate a DictClass object that provides specific information about the class, such as whether the class is abstract, final, or an interface; which class it extends; whether it implements any interfaces; and what methods it includes. Notice that the DictClass class can also reflect on interfaces. Also notice how the class counter is converted into a class ID; this conversion is required because the IDs aren’t listed consecutively.

When you run this job, you’ll notice that it’s much slower than the implementation that uses the table data API—at least the first time you run it! The job performs better after the information is cached.

Figure 1 shows the object model for the dictionary API. As you can see, some elements can’t be reflected upon by using this API.

Figure 1. The object model for the dictionary reflection API


The following example revises the FindStaticMethodsOnCustTable from the preceding code by using the dictionary API. It also reports the method parameters of the methods.

static void findStaticMethodsOnCustTable(Args _args)
{
DictTable dictTable = new DictTable(tableNum(CustTable));
DictMethod dictMethod;
int i;
int j;
str parameters;

for (i=1; i<=dictTable.staticMethodCnt(); i++)
{
dictMethod = new DictMethod(
UtilElementType::TableStaticMethod,
dictTable.id(),
dictTable.staticMethod(i));

parameters = '';
for (j=1; j<=dictMethod.parameterCnt(); j++)
{
parameters += strfmt("%1 %2",
extendedTypeId2name(dictMethod.parameterId(j)),
dictMethod.parameterName(j));

if (j<dictMethod.parameterCnt())
parameters += ', ';
}
info(strfmt("%1(%2)", dictMethod.name(), parameters));
}
}



As mentioned earlier, reflection can also be used to invoke methods on objects. This example invokes the static Find method on the table CustTable.

static void invokeFindOnCustTable(Args _args)
{
DictTable dictTable = new DictTable(tableNum(CustTable));
CustTable customer;
;
customer = dictTable.callStatic(
tableStaticMethodStr(CustTable, Find), '1201');

print customer.Name; //Prints Sparrow Wholesales
pause;
}


Notice the use of the intrinsic function tableStaticMethodStr to make a reference to the Find method.

You can also use this API to instantiate class and table objects. Suppose you want to select all records in a table with a given table ID. The following example shows you how.

void findRecords(TableId _tableId)
{
DictTable dictTable = new DictTable(_tableId);
Common common = dictTable.makeRecord();
FieldId primaryKeyField = DictTable.primaryKeyField();

while select common
{
info(strfmt("%1", common.(primaryKeyField)));
}
}


First, notice the call to the makeRecord method that instantiates a table cursor object that points to the correct table. You can use the select statement to select records from the table. If you wanted to, you could also insert records by using the table cursor. Notice the syntax used to get a field value out of the cursor object; this syntax allows any field to be accessed by its field ID. This example simply prints the content of the primary key field. You can use the makeObject method on the class DictClass to create an object instance of a class.

All the classes in the dictionary API discussed so far are defined as system APIs. On top of each of these is an application-defined class that provides even more reflection capabilities. These classes are named SysDict<Concept>, and each class extends its counterpart in the system API. For example, SysDictClass extends DictClass.

Consider the following example. Table fields have a property that specifies whether the field is mandatory. The DictField class returns the value of the mandatory property as a bit set in the return value of its flag method. Testing of a bit set is somewhat cumbersome, and if the implementation of the flag changes, the consuming applications breaks. The SysDictField class encapsulates the bit-testing logic in a mandatory method. Here is how the method is used.

static void mandatoryFieldsOnCustTable(Args _args)
{
DictTable dictTable = new DictTable(tableNum(CustTable));
SysDictField sysDictField;
int i;

for (i=1; i<=dictTable.fieldCnt(); i++)
{
sysDictField = new SysDictField(
dictTable.id(), dictTable.fieldCnt2Id(i));

if (sysDictField.mandatory())
info(sysDictField.name());
}
}


You might also want to browse the SysDict classes for static methods. Many of these provide additional reflection information and better interfaces. For example, the SysDictionary class provides a classes method that has a collection of SysDictClass instances. You could use this method to simplify the earlier findAbstractInventoryClasses example.

Notice how all the examples instantiate the dictionary classes by using their new constructor. Some developers use an alternative way to instantiate the dictionary classes, but you should avoid it. Recall the hierarchy of the objects shown in Figure 1. A parent object can return an instance of a child object, as shown here.

DictTable dictTable = new DictTable(tableId);
DictField firstField, nextField;
firstField = dictTable.fieldObject(dictTable.fieldNext(0));
nextField = dictTable.fieldObject(dictTable.fieldNext(dictField.id()));


The primary reason to avoid this construct is that you can’t substitute Dict classes with SysDict classes. If you ever need reflection methods available only on the SysDict classes, you must refactor the code. Writing the code so that it is easy to substitute the class makes refactoring easier and lowers the risk of introducing bugs in the refactoring process. Another reason to avoid this construct is the lack of API consistency. The examples used in this section that instantiate dictionary classes all follow the same structure, which is consistent for all the classes in the dictionary API.

Other  
  •  Microsoft Dynamic AX 2009 : Reflection System Functions
  •  Microsoft Enterprise Library : Banishing Validation Complication - Diving in With Some Simple Examples (part 4)
  •  Microsoft Enterprise Library : Banishing Validation Complication - Diving in With Some Simple Examples (part 3)
  •  Microsoft Enterprise Library : Banishing Validation Complication - Diving in With Some Simple Examples (part 2)
  •  Microsoft Enterprise Library : Banishing Validation Complication - Diving in With Some Simple Examples (part 1)
  •  Microsoft Enterprise Library : Banishing Validation Complication - How Do I Use The Validation Block?
  •  Microsoft Enterprise Library : Banishing Validation Complication - What Does the Validation Block Do? (part 2)
  •  Microsoft Enterprise Library : Banishing Validation Complication - What Does the Validation Block Do? (part 1)
  •  Microsoft Enterprise Library : A Cache Advance for Your Applications - How Do I Use the Caching Block (part 4) - Refreshing the Cache, Loading the Cache
  •  Microsoft Enterprise Library : A Cache Advance for Your Applications - How Do I Use the Caching Block (part 3) - Removing Items from and Flushing the Cache
  •  
    Top 10
    Extending LINQ to Objects : Writing a Single Element Operator (part 2) - Building the RandomElement Operator
    Extending LINQ to Objects : Writing a Single Element Operator (part 1) - Building Our Own Last Operator
    3 Tips for Maintaining Your Cell Phone Battery (part 2) - Discharge Smart, Use Smart
    3 Tips for Maintaining Your Cell Phone Battery (part 1) - Charge Smart
    OPEL MERIVA : Making a grand entrance
    FORD MONDEO 2.0 ECOBOOST : Modern Mondeo
    BMW 650i COUPE : Sexy retooling of BMW's 6-series
    BMW 120d; M135i - Finely tuned
    PHP Tutorials : Storing Images in MySQL with PHP (part 2) - Creating the HTML, Inserting the Image into MySQL
    PHP Tutorials : Storing Images in MySQL with PHP (part 1) - Why store binary files in MySQL using PHP?
    REVIEW
    - First look: Apple Watch

    - 3 Tips for Maintaining Your Cell Phone Battery (part 1)

    - 3 Tips for Maintaining Your Cell Phone Battery (part 2)
    VIDEO TUTORIAL
    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 1)

    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 2)

    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 3)
    Popular Tags
    Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8 BlackBerry Android Ipad Iphone iOS