运行时类型创建

运行时类型创建(RTTC) (★★★)

#dynamic-prog #rttc #rtti #data-types

概述

运行时类型创建(RTTC)增强了 RTTI,增加了在运行时生成新数据类型的能力(自 SAP Web AS 6.40 起可用)。这意味着可以构建 DDIC 或程序源代码中不存在的类型,然后基于这些动态生成的类型创建数据对象。

📌RTTC 仅创建数据类型
RTTC 可以生成基本类型、结构类型、表类型和引用类型。它不能动态生成类或接口。

CREATE OBJECT 使用动态 TYPE

创建对象时类名在运行时确定:

1
2
3
4
5
6
7
8
9
DATA: oref TYPE REF TO object.

" 动态类名
CREATE OBJECT oref TYPE (lv_classname).

" 使用参数表
DATA: pt TYPE abap_parmbind_tab.
CREATE OBJECT oref TYPE (lv_classname)
PARAMETER-TABLE pt.
变体 语法 使用场景
静态类型 CREATE OBJECT oref TYPE lcl_my_class 编译时已知
动态类型 CREATE OBJECT oref TYPE (lv_name) 类名来自变量
带参数表 CREATE OBJECT oref TYPE (lv_name) PARAMETER-TABLE pt 动态构造函数参数
💡对象引用类型
对于动态实例化,将引用声明为 TYPE REF TO object(泛型),之后如需可向下转型(?=)到具体类型。

CREATE DATA:动态数据对象创建

CREATE DATA 为通过数据引用访问的匿名数据对象分配内存。

变体

变体 语法 类型来源
隐式 CREATE DATA dref. 从引用变量的静态类型
显式静态 CREATE DATA dref TYPE i. 内置、命名或 LIKE 类型
显式表 CREATE DATA dref TYPE TABLE OF typ. 指定类型的表
动态名称 CREATE DATA dref TYPE (lv_typename). 类型名在变量中
RTTC 句柄 CREATE DATA dref TYPE HANDLE lo_rtti. 从 RTTI/RTTC 描述符对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
DATA: dref TYPE REF TO data.

" 隐式(dref 必须有类型,如 TYPE REF TO string)
CREATE DATA dref. " 创建 STRING 类型的对象

" 显式静态
CREATE DATA dref TYPE string. " 创建 STRING

" 显式命名类型
CREATE DATA dref TYPE zmy_structure. " 创建 DDIC 结构

" 动态类型名称
DATA(lv_type) = 'STRING'.
CREATE DATA dref TYPE (lv_type). " 运行时解析类型

" 表类型
CREATE DATA dref TYPE STANDARD TABLE OF string WITH EMPTY KEY.

" RTTC 句柄(最灵活)
DATA(lo_elem) = cl_abap_elemdescr=>get_string( ).
CREATE DATA dref TYPE HANDLE lo_elem. " 从描述符创建 STRING

访问匿名数据对象

1
2
3
4
5
FIELD-SYMBOLS: <fs> TYPE any.

CREATE DATA dref TYPE string.
ASSIGN dref->* TO <fs>.
<fs> = 'Dynamic content'.
⚠️始终使用 ASSIGN 访问
CREATE DATA 后,匿名数据对象只能通过数据引用访问。使用 ASSIGN dref->* TO <fs> 来操作内容。

RTTC 类型创建方法

CL_ABAP_ELEMDESCR – 基本类型

方法 创建类型 参数
GET_I() i
GET_F() f
GET_C( len ) c 长度
GET_STRING() string
GET_X( len ) x 长度
GET_XSTRING() xstring
GET_P( len decimals ) p 长度、小数位
GET_N( len ) n 长度
GET_D() d
GET_T() t
1
2
3
" 创建带 10 位数字和 2 位小数的压缩类型
DATA(lo_p) = cl_abap_elemdescr=>get_p( p_length = 5 p_decimals = 2 ).
CREATE DATA dref TYPE HANDLE lo_p.

CL_ABAP_STRUCTDESCR – 结构类型

从组件列表创建结构:

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

" 构建组件表
APPEND VALUE #( name = 'ID' type = cl_abap_elemdescr=>get_i( ) ) TO lt_comp.
APPEND VALUE #( name = 'NAME' type = cl_abap_elemdescr=>get_string( ) ) TO lt_comp.
APPEND VALUE #( name = 'AMT' type = cl_abap_elemdescr=>get_p( p_length = 8 p_decimals = 2 ) ) TO lt_comp.

" 创建结构描述符
lo_struct = cl_abap_structdescr=>create( p_components = lt_comp ).

" 使用动态结构类型创建数据对象
CREATE DATA dref TYPE HANDLE lo_struct.
ASSIGN dref->* TO FIELD-SYMBOL(<fs>).

" 访问组件
ASSIGN COMPONENT 'ID' OF STRUCTURE <fs> TO FIELD-SYMBOL(<id>).
<id> = 42.
参数 类型 含义
p_components component_table 名称 + 类型描述符对的列表
p_strict abap_bool 严格模式(默认 = abap_true)

CL_ABAP_TABLEDESCR – 表类型

从行类型和键定义创建表类型:

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

" 获取行类型(从已有结构或 RTTC 创建的类型)
lo_line = cl_abap_typedescr=>describe_by_name( 'SPFLI' ).

" 创建标准表类型
lo_table = cl_abap_tabledescr=>create(
p_line_type = lo_line
p_table_kind = cl_abap_tabledescr=>tablekind_standard
p_unique = abap_false
).

" 创建数据对象
CREATE DATA dref TYPE HANDLE lo_table.
ASSIGN dref->* TO FIELD-SYMBOL(<ft>).
参数 类型 含义
p_line_type REF TO cl_abap_datadescr 行类型的描述符
p_table_kind tablekind tablekind_standardtablekind_sortedtablekind_hashed
p_unique abap_bool 是否唯一键?
p_key key_table 键组件
p_key_kind keydefkind keydefkind_defaultkeydefkind_table_linekeydefkind_user

CL_ABAP_REFDESCR – 引用类型

创建引用类型描述符:

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

lo_base = cl_abap_elemdescr=>get_i( ).
lo_ref = cl_abap_refdescr=>create( p_base_type = lo_base ).

" 创建 TYPE REF TO i
CREATE DATA dref TYPE HANDLE lo_ref.
参数 类型 含义
p_base_type REF TO cl_abap_datadescr 引用指向的类型

完整示例:从 DDIC 结构动态创建表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
DATA: dref TYPE REF TO data.
FIELD-SYMBOLS: <ft> TYPE ANY TABLE.

" 步骤 1:从 DDIC 获取行类型描述符
DATA(lo_line) = cl_abap_structdescr=>describe_by_name( 'SFLIGHT' ).

" 步骤 2:创建表类型描述符
DATA(lo_tab) = cl_abap_tabledescr=>create(
p_line_type = lo_line
p_table_kind = cl_abap_tabledescr=>tablekind_sorted
p_unique = abap_true
p_key = VALUE #(
( name = 'CARRID' )
( name = 'CONNID' )
( name = 'FLDATE' ) )
).

" 步骤 3:创建数据对象
CREATE DATA dref TYPE HANDLE lo_tab.

" 步骤 4:访问
ASSIGN dref->* TO <ft>.
SELECT * FROM sflight INTO TABLE @<ft>.

流程图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
DDIC / 已有类型
|
v
describe_by_name() 或 describe_by_data()
|
v
行类型描述符 (CL_ABAP_STRUCTDESCR)
|
v
CL_ABAP_TABLEDESCR=>create( line_type, key, ... )
|
v
表类型描述符 (CL_ABAP_TABLEDESCR)
|
v
CREATE DATA dref TYPE HANDLE <descriptor>
|
v
ASSIGN dref->* TO <ft>
|
v
像普通内表一样使用 <ft>

CREATE DATA 汇总表

你想要的 如何创建
简单类型变量 CREATE DATA dref TYPE typename
从运行时名称的变量 CREATE DATA dref TYPE (lv_name)
从组件的结构 构建组件表,CL_ABAP_STRUCTDESCR=>create()TYPE HANDLE
从任意行类型的表 CL_ABAP_TABLEDESCR=>create()TYPE HANDLE
引用类型 CL_ABAP_REFDESCR=>create()TYPE HANDLE
已知类型的匿名数据对象 CREATE DATA dref TYPE ... + ASSIGN dref->*

比较:RTTI vs RTTC

方面 RTTI RTTC
用途 检查已有类型 在运行时创建新类型
输入 数据对象、类型名称、引用 组件列表、类型描述符
输出 带元数据的类型描述符 新类型描述符 + 数据对象
相同层次结构(CL_ABAP_*DESCR) 子类增加 create() 方法
限制 不能创建类型 不能创建类/接口
SAP 版本 始终可用 SAP Web AS 6.40+
📌RTTC 限制
RTTC 可以生成数据类型(基本、结构、表、引用),但不能生成类或接口。动态类实例化仅使用已有类。

考试/测试模式

关键词 / 短语 答案
“RTTC 用途” 在运行时生成新数据类型
“CREATE DATA TYPE HANDLE” 使用 RTTI/RTTC 描述符对象确定类型
“CREATE DATA TYPE (name)” 类型名从变量动态解析
“CL_ABAP_STRUCTDESCR=>create 参数” p_components – 名称 + 类型对的组件表
“CL_ABAP_TABLEDESCR=>create 参数” p_line_typep_table_kindp_uniquep_key
“CREATE DATA 后访问” ASSIGN dref->* TO <fs>
“CREATE OBJECT 动态 TYPE” CREATE OBJECT oref TYPE (lv_classname)
“RTTC 不能创建” 类和接口 – 仅数据类型
“CREATE DATA 隐式” 从引用变量声明的静态类型
“RTTC 最低 SAP 版本” SAP Web AS 6.40
“基本类型创建方法” CL_ABAP_ELEMDESCR=>GET_C()GET_I()GET_P()
“匿名数据对象” CREATE DATA 创建,通过数据引用访问

相关笔记