TypeId浅析
AX提供了一些内置函数用来获取数据的类型,比如Typeof(),比如ClassIdGet(),TypeId().
这里只讨论一下TypeId(),查了半天都没找到关于这个函数的描述,倒是Inside AX这本书对TypeOf()有所描述:
Typeof()这个系统函数以变量实例为入参,返回入参对应的基本类型,比如下面的例子:
*** 错误: 97,FunctionModuleID 的参数不是模块。
从上面的两个函数我们就可以推测出typeId()这个函数的返回值是什么了。
猜想的话,这些信息应该存在了AOD文件里,typeId()这个函数取得了该信息。
如果用typeId来取得EDT类型的Id,代码应该类似下面代码的样子:
typeId()这个方法还是有其用武之地的,在有些场景下需要传入的参数带有其原始数据类型信息,比如最常见的Runbase框架下通过代码添加控件的情况,服务端代码需要知道客户端代码是否为UserType(即:EDT类型)然后做相应的处理,这时用typeId()这个方法就方便多了,否则客户端每次调用还要传一个参数过去表示是否为UserType,估计会不怎么爽,呵呵。
当然typeId()这个方法可能还有其他用武之地。
这里只讨论一下TypeId(),查了半天都没找到关于这个函数的描述,倒是Inside AX这本书对TypeOf()有所描述:
Typeof()这个系统函数以变量实例为入参,返回入参对应的基本类型,比如下面的例子:
int i = 123;
str s = "Hello world";
MyClass c;
Guid g = newGuid();
print typeOf(i); //Prints Integer
print typeOf(s); //Prints String
print typeOf(c); //Prints Class
print typeOf(g); //Prints Guid
pause;
它的返回值是Types这个系统枚举类型的一个值,该枚举类型为X++中所有的基本类型包含一个值。当然我们可以用如下方法打印出Types这个系统枚举类型对应的值。str s = "Hello world";
MyClass c;
Guid g = newGuid();
print typeOf(i); //Prints Integer
print typeOf(s); //Prints String
print typeOf(c); //Prints Class
print typeOf(g); //Prints Guid
pause;
static void Types(Args _args)
{
DictEnum dictEnum = new DictEnum(enumNum(Types));
int i;
;
for(i=0;i<dictEnum.values();i++)
{
info(int2str(dictEnum.index2Value(i)));
info(dictEnum.index2Label(i));
}
}
接下来再看TypeId这个函数,在Global这个类中我们可以看到有如下方法:{
DictEnum dictEnum = new DictEnum(enumNum(Types));
int i;
;
for(i=0;i<dictEnum.values();i++)
{
info(int2str(dictEnum.index2Value(i)));
info(dictEnum.index2Label(i));
}
}
/*
Returns a valid Extended Data Type Id, given the argument in the form the system function typeId returns
*/
static extendedTypeId typeId2ExtendedTypeId(int _extendedType)
{
if ((_extendedType & 0xffff) != Types::UserType)
throw error(strfmt("@SYS26445",funcname()));
return _extendedType >> 16 & 0xffff;
}
当然还有个类似的方法:Returns a valid Extended Data Type Id, given the argument in the form the system function typeId returns
*/
static extendedTypeId typeId2ExtendedTypeId(int _extendedType)
{
if ((_extendedType & 0xffff) != Types::UserType)
throw error(strfmt("@SYS26445",funcname()));
return _extendedType >> 16 & 0xffff;
}
/*
Returns a valid Enum Id, given the argument in the form the system function typeId returns.
Consider use the enumNum intrinsic function, instead of this function!
*/
static enumId typeId2EnumId(enumId _enumId)
{
if ((_enumId & 0xffff) != Types::Enum)
throw error(strfmt("@SYS23815",funcname()));
return _enumId >> 16 & 0xffff;
}
从函数说明可以看出,这两个方法的入参都是函数TypeId()的返回值。我试了一下TypeId()这个方法的入参只能是EDT或者Enum类型(当然由于没有看到相关的文档,只是我测试的结果,可能不准确),其他类型做入参的时候就报错说:Returns a valid Enum Id, given the argument in the form the system function typeId returns.
Consider use the enumNum intrinsic function, instead of this function!
*/
static enumId typeId2EnumId(enumId _enumId)
{
if ((_enumId & 0xffff) != Types::Enum)
throw error(strfmt("@SYS23815",funcname()));
return _enumId >> 16 & 0xffff;
}
*** 错误: 97,FunctionModuleID 的参数不是模块。
从上面的两个函数我们就可以推测出typeId()这个函数的返回值是什么了。
if ((_extendedType & 0xffff) != Types::UserType)
throw error(strfmt("@SYS26445",funcname()));
typeId()函数的返回值与0xffff做按位与运算显然是要屏蔽其返回值的高16位,从而取得低16位,而与运算的结果与Types类型做比较,显然其低16位对应的是EDT类型(或者枚举类型)对应的原始类型,当然枚举类型对应的是Types::Enum,EDT类型对应的是Types::UserType.throw error(strfmt("@SYS26445",funcname()));
return _extendedType >> 16 & 0xffff;
右移16位,然后跟0xffff按位与,返回的是EDT类型(或者枚举类型)的ID,那显然typeId()方法返回值的高16位对应的是EDT类型(或者枚举类型)的ID了。猜想的话,这些信息应该存在了AOD文件里,typeId()这个函数取得了该信息。
如果用typeId来取得EDT类型的Id,代码应该类似下面代码的样子:
typeId2ExtendedTypeId(typeId(AccountNum));
要调用两个函数,其实如果单纯取得EDT类型或者Enum类型的ID不需要这么周折,完全可以用一个内置函数来实现:extendedTypeNum(AccountNum);
当然Enum有对应的EnumNum()这个内置函数,看上去后面的方法简洁多了。typeId()这个方法还是有其用武之地的,在有些场景下需要传入的参数带有其原始数据类型信息,比如最常见的Runbase框架下通过代码添加控件的情况,服务端代码需要知道客户端代码是否为UserType(即:EDT类型)然后做相应的处理,这时用typeId()这个方法就方便多了,否则客户端每次调用还要传一个参数过去表示是否为UserType,估计会不怎么爽,呵呵。
当然typeId()这个方法可能还有其他用武之地。