运行时类型识别

运行时类型识别(RTTI) (★★★)

#dynamic-prog #rtti #data-types

概述

运行时类型识别(RTTI)允许使用类型描述对象在运行时描述数据类型和对象类型。每种 ABAP 类型映射到一个特定的 RTTI 类实例,提供关于类型结构、组件和属性的元数据。

RTTI 类层次结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
CL_ABAP_TYPEDESCR(根类)
| kind: kind_elem, kind_struct, kind_table, kind_ref, kind_class, kind_intf
| 方法: describe_by_name(), describe_by_data(), describe_by_object_ref()
|
+-- CL_ABAP_DATADESCR
| | +-- CL_ABAP_ELEMDESCR
| | 内置类型: GET_I, GET_F, GET_C, GET_STRING, GET_P ...
| | DDIC: get_ddic_field_list()
| |
| +-- CL_ABAP_REFDESCR
| | get_ref_type() -> 基础类型描述符
| |
| +-- CL_ABAP_STRUCTDESCR
| | get_components() -> 组件表
| | get_ddic_field_list() -> DDIC 字段信息
| |
| +-- CL_ABAP_TABLEDESCR
| | get_table_line_type() -> 行类型描述符
| | key: 表键信息
| |
| +-- CL_ABAP_ENUMDESCR
|
+-- CL_ABAP_OBJECTDESCR
+-- CL_ABAP_CLASSDESCR
| 方法、属性、继承信息
+-- CL_ABAP_INTFDESCR
接口方法信息

关键工厂方法(CL_ABAP_TYPEDESCR)

方法 用途 返回值
describe_by_name( name ) 获取命名类型的描述符(DDIC/全局) 类型描述符对象
describe_by_data( dobj ) 从数据对象获取描述符 类型描述符对象
describe_by_object_ref( ref ) 从对象引用获取描述符 对象类型描述符
describe_by_ref( ref ) 从数据引用获取描述符 类型描述符对象
1
2
3
4
5
6
7
8
" 通过数据对象
DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( lv_value ).

" 通过类型名称
DATA(lo_descr) = cl_abap_typedescr=>describe_by_name( 'STRING' ).

" 通过对象引用
DATA(lo_obj_descr) = cl_abap_typedescr=>describe_by_object_ref( oref ).

KIND 属性值

常量 描述符类 含义
kind_elem E CL_ABAP_ELEMDESCR 基本类型
kind_struct S CL_ABAP_STRUCTDESCR 结构类型
kind_table T CL_ABAP_TABLEDESCR 内表类型
kind_ref R CL_ABAP_REFDESCR 引用类型
kind_class C CL_ABAP_CLASSDESCR 类类型
kind_intf I CL_ABAP_INTFDESCR 接口类型
1
2
3
4
5
6
7
8
CASE lo_descr->kind.
WHEN cl_abap_typedescr=>kind_elem.
" 基本类型
WHEN cl_abap_typedescr=>kind_struct.
" 结构
WHEN cl_abap_typedescr=>kind_table.
" 内表
ENDCASE.

CL_ABAP_ELEMDESCR

描述基本(内置)类型。

1
2
3
4
5
6
7
8
DATA: lo_elem TYPE REF TO cl_abap_elemdescr.
lo_elem ?= cl_abap_typedescr=>describe_by_data( lv_string ).

" 访问属性
WRITE: / lo_elem->type_kind, " 类型种类字符
lo_elem->length, " 内部长度
lo_elem->output_length, " 输出长度
lo_elem->decimals. " 小数位数(类型 p)
属性 类型 含义
type_kind typekind 单字符:CNIPFDTg(string)、y(xstring) …
length i 内部长度(字节)
output_length i 输出长度
decimals i 小数位数

内置类型的静态工厂方法

方法 创建以下类型的描述符
GET_C( len ) 类型 c,指定长度
GET_N( len ) 类型 n,指定长度
GET_X( len ) 类型 x,指定长度
GET_P( len decimals ) 类型 p,指定长度和小数位
GET_I() 类型 i
GET_F() 类型 f
GET_STRING() 类型 string
GET_XSTRING() 类型 xstring

CL_ABAP_STRUCTDESCR

描述结构化类型并提供对组件的访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DATA: lo_struct TYPE REF TO cl_abap_structdescr.
DATA: lt_comp TYPE cl_abap_structdescr=>component_table.

lo_struct ?= cl_abap_typedescr=>describe_by_data( ls_any_struct ).

" 获取组件列表
lt_comp = lo_struct->get_components( ).
LOOP AT lt_comp INTO DATA(ls_comp).
WRITE: / ls_comp-name, ls_comp-type->kind.
ENDLOOP.

" 获取 DDIC 字段列表(用于 DDIC 结构)
DATA: lt_ddic TYPE ddfields.
lt_ddic = lo_struct->get_ddic_field_list( ).
方法 返回值 用途
get_components() component_table 所有组件及名称、类型描述符
get_ddic_field_list() ddfields DDIC 元数据(域、数据元素、文本)

组件表结构

字段 类型 内容
name string 组件名称
type REF TO cl_abap_datadescr 组件的类型描述符
as_include abap_bool 是否为 include 结构?
suffix string include 命名冲突的后缀

CL_ABAP_TABLEDESCR

描述内表类型。

1
2
3
4
5
6
7
8
9
10
11
DATA: lo_table TYPE REF TO cl_abap_tabledescr.
DATA: lo_line TYPE REF TO cl_abap_datadescr.

lo_table ?= cl_abap_typedescr=>describe_by_data( lt_any_table ).

" 获取行类型
lo_line = lo_table->get_table_line_type( ).

" 访问表类别和键
WRITE: / lo_table->table_kind, " tablekind_standard/sorted/hashed
lo_table->key. " 键信息
属性 含义
table_kind tablekind_standardtablekind_sortedtablekind_hashed
key 键组件和键类别
key_defkind 键定义类型:default、table line、user、empty
方法 返回值 用途
get_table_line_type() REF TO cl_abap_datadescr 行类型的描述符

CL_ABAP_REFDESCR

描述引用类型。

1
2
3
4
5
DATA: lo_ref  TYPE REF TO cl_abap_refdescr.
DATA: lo_base TYPE REF TO cl_abap_datadescr.

lo_ref ?= cl_abap_typedescr=>describe_by_data( dref_any ).
lo_base = lo_ref->get_referenced_type( ). " 它指向什么?

CL_ABAP_OBJECTDESCR(及子类)

描述类和接口。

1
2
3
4
5
6
7
8
DATA: lo_class TYPE REF TO cl_abap_classdescr.

lo_class ?= cl_abap_typedescr=>describe_by_object_ref( oref ).

" 访问方法和属性
LOOP AT lo_class->methods INTO DATA(ls_meth).
WRITE: / ls_meth-name.
ENDLOOP.
子类 关键属性
CL_ABAP_CLASSDESCR methodsattributessuper_class
CL_ABAP_INTFDESCR methodsattributes(接口的)

DESCRIBE FIELD 语句

一种更简单的、基于语句的基本类型信息获取方式:

1
2
3
4
5
6
7
8
9
10
DATA: lv_type    TYPE c LENGTH 1.
DATA: lv_length TYPE i.
DATA: lv_olength TYPE i.
DATA: lv_decimals TYPE i.

DESCRIBE FIELD lv_data
TYPE lv_type
LENGTH lv_length IN BYTE MODE
OUTPUT-LENGTH lv_olength
DECIMALS lv_decimals.
附加项 返回值 说明
TYPE typ 单字符类型种类 CIPFg
LENGTH n 内部长度 使用 IN BYTE MODEIN CHARACTER MODE
OUTPUT-LENGTH n 输出长度
DECIMALS n 小数位数 仅对类型 p 有意义
💡DESCRIBE FIELD vs RTTI
DESCRIBE FIELD 在快速检查时更简单。RTTI 提供更丰富的元数据并能处理复杂类型(结构、表)。超出基本类型/长度查询的场景优先使用 RTTI。

RTTI 类型解析流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
数据对象 / 类型名称 / 对象引用
|
v
describe_by_*() --> CL_ABAP_TYPEDESCR
| |
v v
检查 ->kind 向下转型 (?=) 到具体类
| |
v v
kind_elem? --> CL_ABAP_ELEMDESCR --> type_kind, length, decimals
kind_struct? --> CL_ABAP_STRUCTDESCR --> get_components(), get_ddic_field_list()
kind_table? --> CL_ABAP_TABLEDESCR --> get_table_line_type(), key
kind_ref? --> CL_ABAP_REFDESCR --> get_referenced_type()
kind_class? --> CL_ABAP_CLASSDESCR --> methods, attributes
kind_intf? --> CL_ABAP_INTFDESCR --> methods, attributes

考试/测试模式

关键词 / 短语 答案
“RTTI 根类” CL_ABAP_TYPEDESCR
“从数据对象获取描述符” describe_by_data( dobj )
“从类型名称获取描述符” describe_by_name( 'TYPE_NAME' )
“从对象引用获取描述符” describe_by_object_ref( oref )
“KIND 属性值” kind_elemkind_structkind_tablekind_refkind_classkind_intf
“获取结构组件” CL_ABAP_STRUCTDESCR=>get_components()
“获取 DDIC 字段信息” CL_ABAP_STRUCTDESCR=>get_ddic_field_list()
“获取表行类型” CL_ABAP_TABLEDESCR=>get_table_line_type()
“DESCRIBE FIELD 返回类型种类” 单字符:TYPE typ 附加项
“RTTI 向下转型运算符” ?=(从基类到具体描述符的窄化转型)
“基本类型属性” type_kindlengthoutput_lengthdecimals
“引用类型的基础类型” CL_ABAP_REFDESCR=>get_referenced_type()

相关笔记