动态编程技术 (★★)
#dynamic-prog
概述
动态编程是指在运行时而非设计时指定类型、长度、偏移量或名称。这使得程序能灵活、通用地适应不同的数据结构和用户输入。
技术一览
| 技术 |
机制 |
典型用途 |
| 动态语言元素 |
运行时替换令牌 |
通用工具 |
| 字段符号 |
动态数据访问 |
处理未知结构 |
| RTTI / RTTC |
类型检查和创建 |
框架、工具 |
| 程序生成 |
运行时创建并执行代码 |
动态报表 |
令牌替换
有两种方式使语句动态化:
| 令牌类型 |
语法 |
示例 |
关键规则 |
| 替换字面量 |
数据对象直接在语句中 |
WRITE: / var. |
值替换字面量 |
| 替换标识符 |
数据对象放在括号中 |
WRITE: / (lv_field). |
值替换名称;括号内不能有空格 |
CALL FUNCTION (lv_name) 是正确的。
CALL FUNCTION ( lv_name ) 是错误的,会导致语法错误或意外行为。
动态 Open SQL
1 2 3 4 5 6 7 8 9 10
| " 动态表名 SELECT * FROM (lv_tabname) INTO TABLE @lt_data.
" 动态 WHERE 条件 SELECT * FROM spfli INTO TABLE @lt_flights WHERE (lv_where_clause).
" 两者都动态 SELECT * FROM (lv_tab) INTO TABLE @lt_result WHERE (lv_cond).
|
| SQL 子句 |
动态语法 |
说明 |
FROM |
(lv_tabname) |
表名在变量中 |
WHERE |
(lv_condition) |
整个条件作为字符串 |
| 字段列表 |
不能完全动态 |
使用 * 或静态指定列 |
动态函数模块调用
1 2 3 4 5 6 7 8 9
| DATA: lv_fm_name TYPE funcname VALUE 'Z_MY_FUNCTION'.
CALL FUNCTION (lv_fm_name) EXPORTING iv_param = lv_value IMPORTING ev_result = lv_result EXCEPTIONS others = 1.
|
当函数模块名称在运行时确定时(例如从定制表或用户选择中获取),使用动态 FM 调用。
动态方法调用
1 2 3 4 5 6
| DATA: pt TYPE abap_parmbind_tab, et TYPE abap_excpbind_tab.
CALL METHOD (lv_method_name) PARAMETER-TABLE pt EXCEPTION-TABLE et.
|
| 附加项 |
用途 |
PARAMETER-TABLE |
通过内表动态传递参数 |
EXCEPTION-TABLE |
通过内表动态处理异常 |
参数表行包含 name(参数名)和 value(实际参数的引用)。异常表行包含 name(异常名)和 value(要分配的 sy-subrc 值)。
使用动态数据的 CALL TRANSACTION
1 2 3 4 5 6 7
| DATA: lt_bdcdata TYPE TABLE OF bdcdata.
" 动态填充 BDC 表... CALL TRANSACTION 'MM01' USING lt_bdcdata MODE 'N' UPDATE 'S' MESSAGES INTO lt_messages.
|
程序生成
INSERT REPORT
1 2
| " 从源代码内表生成程序 INSERT REPORT lv_prog_name FROM lt_source_code.
|
| 方面 |
详情 |
| 来源 |
string 或类似类型的内表 |
| 结果 |
程序被添加到仓库(临时或可传输) |
| 使用场景 |
动态报表生成 |
GENERATE SUBROUTINE POOL
1 2 3 4 5 6 7 8 9 10
| DATA: lv_prog TYPE string.
GENERATE SUBROUTINE POOL lt_source NAME lv_prog MESSAGE lv_msg LINE lv_line WORD lv_word.
" 调用生成的子程序 PERFORM (lv_form_name) IN PROGRAM (lv_prog).
|
| 方面 |
详情 |
| 用途 |
生成并执行临时子程序池 |
| 生命周期 |
仅在内部会话期间存在 |
| 错误处理 |
MESSAGE、LINE、WORD 附加项捕获语法错误 |
程序生成在运行时创建新的可执行代码。动态调用(FM、方法)调用的是名称在运行时解析的已有代码。生成代价更高,应谨慎使用。
比较:静态 vs 动态
| 方面 |
静态 |
动态 |
| 语法检查 |
完整的编译时检查 |
仅在运行时发现错误 |
| 性能 |
最优 |
名称解析有轻微开销 |
| 灵活性 |
固定 |
适应运行时条件 |
| 安全性 |
高(编译器捕获) |
较低(可能出现运行时错误) |
| 调试 |
直接 |
更难追踪 |
动态规格绕过语法检查。拼写错误的名称、错误的类型或缺失的对象会导致运行时错误(短转储),编译器无法捕获。使用前始终验证动态输入。
考试/测试模式
| 关键词 / 短语 |
答案 |
| “动态标识符语法” |
数据对象在括号中,不能有空格:(lv_name) |
| “动态令牌替换字面量” |
数据对象直接用在语句位置 |
| “SELECT 中动态 WHERE” |
WHERE (lv_condition),条件为字符串变量 |
| “CALL FUNCTION 动态” |
CALL FUNCTION (lv_fm_name) |
| “动态方法参数传递” |
PARAMETER-TABLE pt,使用 abap_parmbind_tab |
| “INSERT REPORT 用途” |
从源代码表在仓库中创建程序 |
| “GENERATE SUBROUTINE POOL” |
从源代码创建临时可执行子程序池 |
| “动态编程的主要风险” |
语法检查无法检测的运行时错误 |
相关笔记