All checks were successful
NTFY Notification / notify (push) Successful in 3s
Add detailed documentation for error handling system including: - Error handling architecture with class diagrams - Error type classification (7 types) - Complete error handling lifecycle sequence diagrams - Module-specific error handling patterns (M01/M03/M05/M06/M07/M08/M09) - Error recovery strategies (continue, graceful degradation, warning only) - Error report generation process - Best practices with code examples - Test coverage overview - Quick reference guide Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
30 KiB
30 KiB
错误处理机制详解
目录
系统概述
AutoBOM系统采用集中式日志记录 + 持续处理的错误处理策略,确保在批量处理BOM数据时,单个记录的错误不会中断整个处理流程。
核心设计原则
- 错误隔离: 单个记录错误不影响其他记录处理
- 错误累积: 所有错误统一收集,集中展示
- 上下文保留: 记录完整的错误上下文信息
- 用户友好: 提供清晰的错误描述和定位信息
设计优势
graph LR
subgraph "传统错误处理"
A1[遇到错误] --> B1[停止处理]
B1 --> C1[用户修复]
C1 --> D1[重新运行]
D1 --> E1[下一个错误<br/>再次停止]
end
subgraph "AutoBOM错误处理"
A2[遇到错误] --> B2[记录错误]
B2 --> C2[继续处理]
C2 --> D2[处理完成]
D2 --> E2[一次性查看<br/>所有错误]
end
style A2 fill:#c8e6c9
style B2 fill:#c8e6c9
style C2 fill:#c8e6c9
style D2 fill:#c8e6c9
style E2 fill:#c8e6c9
style A1 fill:#ffcdd2
style E1 fill:#ffcdd2
错误处理架构
类层次结构
classDiagram
class clsErrorLogger {
-Collection pErrors
+Record(rowIdx, sourceFunc, errorType, desc, context)
+HasErrors() Boolean
+PrintReport(targetWb)
+Class_Initialize()
}
class M01_Main {
+RunBOMConversion()
+GeneratePreprocessingReport()
}
class M03_Logic {
-clsErrorLogger g_Logger
+InitLogic(logger)
+ParseRule(strRule, rowIdx)
-ConflictDetection()
}
class M05_PreProcessor {
-clsErrorLogger g_Logger
+InitPreProcessor(logger, wsMapping)
+PreprocessCondition(strCond, strCat, rowIdx)
}
class M06_ModelParser {
-clsErrorLogger g_Logger
+InitModelParser(logger)
+ParseProductModel(modelString)
}
class M07_BOMMatcher {
-clsErrorLogger g_Logger
+InitBOMMatcher(logger)
+MatchBOMRecord(ws, params)
}
class M08_ComponentProcessor {
-clsErrorLogger g_Logger
+InitComponentProcessor(logger)
+ProcessComponentRecord(row)
}
class M09_BOMExtractor {
-clsErrorLogger g_Logger
+RunBOMExtraction()
+ProcessSingleModel(modelString)
}
clsErrorLogger <-- M01_Main : uses
clsErrorLogger <-- M03_Logic : uses
clsErrorLogger <-- M05_PreProcessor : uses
clsErrorLogger <-- M06_ModelParser : uses
clsErrorLogger <-- M07_BOMMatcher : uses
clsErrorLogger <-- M08_ComponentProcessor : uses
clsErrorLogger <-- M09_BOMExtractor : uses
模块依赖关系
graph TB
Logger[clsErrorLogger.cls<br/>错误日志记录器]
M01[M01_Main.bas<br/>主入口]
M03[M03_Logic.bas<br/>条件解析]
M05[M05_PreProcessor.bas<br/>预处理]
M06[M06_ModelParser.bas<br/>型号解析]
M07[M07_BOMMatcher.bas<br/>BOM匹配]
M08[M08_ComponentProcessor.bas<br/>部件处理]
M09[M09_BOMExtractor.bas<br/>BOM提取]
M01 --> Logger
M01 --> M03
M01 --> M05
M09 --> Logger
M09 --> M06
M09 --> M07
M09 --> M08
M03 -.记录错误.-> Logger
M05 -.记录错误.-> Logger
M06 -.记录错误.-> Logger
M07 -.记录错误.-> Logger
M08 -.记录错误.-> Logger
Logger -.生成报告.-> M01
Logger -.生成报告.-> M09
style Logger fill:#e1f5fe
style M01 fill:#fff4e1
style M09 fill:#fff4e1
错误类型与分类
错误分类体系
graph TD
Root[错误类型]
Root --> Sys[系统错误<br/>SystemError]
Root --> Syn[语法错误<br/>SyntaxError]
Root --> Log[逻辑冲突<br/>LogicConflict]
Root --> Map[映射警告<br/>MappingWarning]
Root --> Mod[型号解析错误<br/>ModelParseError]
Root --> Mat[BOM匹配错误<br/>BOMMatchError]
Root --> Val[验证错误<br/>ValidationError]
Sys --> Sys1[运行时异常]
Sys --> Sys2[空引用错误]
Sys --> Sys3[类型转换错误]
Syn --> Syn1[缺少运算符]
Syn --> Syn2[括号不匹配]
Syn --> Syn3[非法字符]
Log --> Log1[相等与不等冲突]
Log --> Log2[互斥值冲突]
Map --> Map1[azxs映射缺失]
Map --> Map2[lcfw映射缺失]
Mod --> Mod1[表头为空]
Mod --> Mod2[格式不匹配]
Mat --> Mat1[无匹配记录]
Mat --> Mat2[多重匹配]
Val --> Val1[组件组合无效]
Val --> Val2[数据不完整]
style Root fill:#e1f5fe
style Sys fill:#ffcdd2
style Syn fill:#fff9c4
style Log fill:#ffe0b2
style Map fill:#c8e6c9
style Mod fill:#c8e6c9
style Mat fill:#c8e6c9
style Val fill:#c8e6c9
错误类型详细说明
| 错误类型 | 英文标识 | 严重级别 | 处理策略 | 示例 |
|---|---|---|---|---|
| 系统错误 | SystemError / System Error | 🔴 高 | 记录并跳过 | 运行时异常、对象为空 |
| 语法错误 | SyntaxError | 🔴 高 | 记录并跳过 | 条件缺少"="或"!=" |
| 逻辑冲突 | LogicConflict | 🟡 中 | 记录并跳过 | azxs=1 AND azxs=2 |
| 映射警告 | MappingWarning | 🟢 低 | 记录并继续 | 值未在映射表中找到 |
| 型号解析错误 | ModelParseError | 🔴 高 | 记录并跳过 | 型号格式不匹配 |
| BOM匹配错误 | BOMMatchError | 🟡 中 | 记录并继续 | 无匹配/多重匹配 |
| 验证错误 | ValidationError | 🟡 中 | 记录并继续 | 组件与子组件混用 |
错误处理流程
完整错误处理生命周期
sequenceDiagram
participant User as 用户
participant Main as M01/M09
participant Logger as clsErrorLogger
participant Module as 业务模块
participant Excel as Excel工作表
User->>Main: 启动处理
Main->>Logger: 创建错误日志记录器
Main->>Main: 初始化各模块
loop 遍历数据行
Main->>Module: 处理单条记录
Module->>Module: 执行业务逻辑
alt 处理成功
Module-->>Main: 返回成功结果
else 发生错误
Module->>Logger: Record(rowIdx, source, type, desc, context)
Logger->>Logger: 存储错误信息到集合
Logger-->>Module: 确认记录
Module-->>Main: 返回Nothing/空结果
Main->>Main: 继续处理下一条记录
end
end
Main->>Logger: HasErrors?
alt 有错误
Logger-->>Main: True
Main->>Logger: PrintReport(targetWb)
Logger->>Excel: 创建"错误报告_hhmmss"工作表
Logger->>Excel: 写入表头(红色背景)
Logger->>Excel: 批量写入错误数据
Logger->>Excel: 自动调整列宽
Main->>User: 显示警告消息框
else 无错误
Logger-->>Main: False
Main->>User: 显示成功消息
end
User-->>Main: 查看错误报告
错误记录数据结构
graph LR
subgraph "错误记录数组"
A[0: 行号<br/>RowIndex]
B[1: 来源模块<br/>SourceFunc]
C[2: 错误类型<br/>ErrorType]
D[3: 详细描述<br/>Description]
E[4: 原始数据<br/>Context]
end
subgraph "示例"
F[<table><tr><td>125</td></tr><tr><td>M03.ParseAtom</td></tr><tr><td>SyntaxError</td></tr><tr><td>No = or != found</td></tr><tr><td>azxsA0</td></tr></table>]
end
A & B & C & D & E --> F
style A fill:#e1f5fe
style B fill:#fff4e1
style C fill:#ffe0b2
style D fill:#c8e6c9
style E fill:#f3e5f5
style F fill:#fafafa
模块错误处理详解
M03_Logic.bas - 条件解析模块
错误场景
flowchart TD
Start[M03_Logic.ParseRule] --> CheckSyntax{检查语法}
CheckSyntax -->|无效| SyntaxErr[语法错误]
CheckSyntax -->|有效| ProcessLogic[处理逻辑]
ProcessLogic --> CheckConflict{检测冲突}
CheckConflict -->|冲突| ConflictErr[逻辑冲突]
CheckConflict -->|无冲突| SystemCheck{系统检查}
SystemCheck -->|异常| SystemErr[系统错误]
SystemCheck -->|正常| Success[解析成功]
SyntaxErr --> LogSyntax[记录: SyntaxError]
ConflictErr --> LogConflict[记录: LogicConflict]
SystemErr --> LogSystem[记录: System Error]
LogSyntax --> Return[返回Nothing]
LogConflict --> Return
LogSystem --> Return
Success --> ReturnResult[返回结果集]
style SyntaxErr fill:#ffcdd2
style ConflictErr fill:#ffe0b2
style SystemErr fill:#ffcdd2
style LogSyntax fill:#fff9c4
style LogConflict fill:#ffe0b2
style LogSystem fill:#ffe0b2
style Return fill:#ffebee
错误处理代码
1. 系统错误处理
ErrorHandler:
g_Logger.Record rowIdx, "M03.ParseRule", "System Error", Err.Description, strRule
Set ParseRule = Nothing
2. 语法错误处理
Else
' 无法解析的格式
If Len(strAtom) > 0 Then
g_Logger.Record rowIdx, "M03.ParseAtom", "Syntax Error", _
"No = or != found", strAtom
End If
End If
3. 逻辑冲突检测
If v1 = Mid(v2, 3) Then
' 等于一个不允许的值
g_Logger.Record rowIdx, "M03.Conflict", "Logic Conflict", _
"Equals disallowed value", k & ": " & v1 & " AND " & v2
Set MergeDictionaries = Nothing: Exit Function
ElseIf v1 = v2 Then
' 相同,无视
ElseIf Left(v1, 2) = "!=" And Left(v2, 2) = "!=" Then
' 都是不等于,合并
res(k) = v1 & "," & v2
Else
' 都是等于,但值不同 → 互斥
g_Logger.Record rowIdx, "M03.Conflict", "Logic Conflict", _
"Mutually Exclusive", k & "=" & v1 & " AND " & v2
Set MergeDictionaries = Nothing: Exit Function
End If
M05_PreProcessor.bas - 预处理模块
错误处理流程
flowchart TD
Start[PreprocessCondition] --> CheckCategory{检查类别}
CheckCategory -->|接头/部件| LoadMapping[加载映射表]
CheckCategory -->|其他| Bypass[跳过预处理]
LoadMapping --> CheckMapping{检查映射}
CheckMapping -->|找到映射| ApplyMapping[应用映射]
CheckMapping -->|未找到| LogWarning[记录映射警告]
ApplyMapping --> MergeOR[合并OR条件]
LogWarning --> MergeOR
MergeOR --> Simplify[简化括号]
Simplify --> Success[返回转换结果]
style CheckMapping fill:#fff9c4
style LogWarning fill:#c8e6c9
style Success fill:#e8f5e9
错误处理代码
映射警告处理
Else
' 记录警告但不中断处理
g_Logger.Record rowIdx, "M05.PreProcessor", "Mapping Warning", _
"Value not found in mapping table: " & keyName & "=" & originalValue, match.Value
End If
M06_ModelParser.bas - 型号解析模块
错误处理流程
flowchart TD
Start[ParseProductModel] --> ExtractHeader[提取表头部分]
ExtractHeader --> CheckEmpty{检查是否为空}
CheckEmpty -->|为空| ParseError[解析错误]
CheckEmpty -->|有值| ParseParams[解析参数]
ParseError --> LogError1[记录: ModelParseError]
LogError1 --> ReturnEmpty[返回空字典]
ParseParams --> SystemCheck{系统检查}
SystemCheck -->|异常| SysError[系统错误]
SystemCheck -->|正常| Success[解析成功]
SysError --> LogError2[记录: SystemError]
LogError2 --> ReturnEmpty2[返回空字典]
Success --> ReturnParams[返回参数字典]
style ParseError fill:#ffcdd2
style SysError fill:#ffcdd2
style LogError1 fill:#ffe0b2
style LogError2 fill:#ffe0b2
style ReturnEmpty fill:#ffebee
style ReturnEmpty2 fill:#ffebee
错误处理代码
1. 解析错误处理
If Len(headerPart) = 0 Then
If Not g_Logger Is Nothing Then
g_Logger.Record 0, "M06.ParseProductModel", "ModelParseError", _
"无法提取表头部分,型号可能为空或格式错误", modelString
End If
Set ParseProductModel = params
Exit Function
End If
2. 系统错误处理
ErrorHandler:
If Not g_Logger Is Nothing Then
g_Logger.Record 0, "M06.ParseProductModel", "SystemError", _
"解析过程发生错误: " & Err.Description, modelString
End If
Set ParseProductModel = CreateObject("Scripting.Dictionary")
M07_BOMMatcher.bas - BOM匹配模块
错误处理流程
flowchart TD
Start[MatchBOMRecord] --> BuildMapping[构建列映射]
BuildMapping --> LoopRows[遍历行]
LoopRows --> Evaluate{评估匹配}
Evaluate -->|匹配| CheckCount{检查数量}
Evaluate -->|不匹配| NextRow[下一行]
CheckCount -->|0条| NoMatch[无匹配]
CheckCount -->|1条| Success[唯一匹配]
CheckCount -->|多条| MultiMatch[多重匹配]
NoMatch --> LogNoMatch[记录: BOMMatchError<br/>未找到匹配]
MultiMatch --> LogMulti[记录: BOMMatchError<br/>多重匹配]
LogNoMatch --> ReturnFail[返回失败结果]
LogMulti --> ReturnFail
Success --> ExtractInfo[提取物料信息]
ExtractInfo --> ExtractErr{提取异常?}
ExtractErr -->|是| LogSysError[记录: SystemError]
ExtractErr -->|否| ReturnSuccess[返回物料信息]
LogSysError --> ReturnEmptyDict[返回空字典]
style NoMatch fill:#ffe0b2
style MultiMatch fill:#ffe0b2
style ExtractErr fill:#ffcdd2
style LogNoMatch fill:#fff9c4
style LogMulti fill:#fff9c4
style LogSysError fill:#ffe0b2
style ReturnFail fill:#ffebee
错误处理代码
1. 匹配结果处理
If matchResult("rowCount") = 0 Then
logger.Record 0, "M09.MatchAllMaterialTypes", "BOMMatchError", _
sheetName & " " & matchResult("message"), ""
End If
2. 系统错误处理
ErrorHandler:
If Not g_Logger Is Nothing Then
g_Logger.Record 0, "M07.MatchBOMRecord", "SystemError", _
"匹配过程发生错误: " & Err.Description, ws.Name
End If
result("success") = False
result("rowCount") = 0
Set result("rowNums") = New Collection
result("message") = "系统错误: " & Err.Description
Set MatchBOMRecord = result
M08_ComponentProcessor.bas - 部件处理模块
错误处理流程
flowchart TD
Start[ProcessComponentRecord] --> ValidateCombination[验证组件组合]
ValidateCombination --> CheckValid{验证结果}
CheckValid -->|无效| ValidationError[验证错误]
CheckValid -->|有效| ExtractComponent[提取组件信息]
ValidationError --> LogError[记录: ValidationError<br/>无效组合]
LogError --> ReturnError[返回错误物料]
ExtractComponent --> ExtractErr{提取异常?}
ExtractErr -->|是| SystemError[系统错误]
ExtractErr -->|否| ReturnSuccess[返回组件信息]
SystemError --> LogSysError[记录: SystemError]
LogSysError --> ReturnError2[返回错误物料]
style ValidationError fill:#ffe0b2
style SystemError fill:#ffcdd2
style LogError fill:#fff9c4
style LogSysError fill:#ffe0b2
style ReturnError fill:#ffebee
style ReturnError2 fill:#ffebee
错误处理代码
系统错误处理
ErrorHandler:
If Not logger Is Nothing Then
logger.Record 0, "M08.ProcessComponentRecord", "SystemError", _
"处理部件记录失败: " & Err.Description, ""
End If
' 返回错误物料信息
Dim errorMat As Object
Set errorMat = CreateObject("Scripting.Dictionary")
errorMat("materialType") = "部件"
errorMat("materialName") = ""
errorMat("materialCode") = ""
errorMat("materialQty") = 0
errorMat("remarks") = "系统错误: " & Err.Description
M09_BOMExtractor.bas - BOM提取模块
错误处理流程
flowchart TD
Start[ProcessSingleModel] --> ParseModel[解析型号]
ParseModel --> ParseOK{解析成功?}
ParseOK -->|失败| LogParseError[记录: ModelParseError]
ParseOK -->|成功| MatchLoop[匹配所有物料类型]
LogParseError --> GenerateErrorRow[生成错误行]
GenerateErrorRow --> Continue[继续下一个型号]
MatchLoop --> MatchCheck{匹配检查}
MatchCheck -->|匹配失败| LogMatchError[记录: BOMMatchError]
MatchCheck -->|匹配成功| SaveResult[保存结果]
LogMatchError --> Continue
SaveResult --> Continue
Continue --> End[结束]
style LogParseError fill:#ffe0b2
style LogMatchError fill:#ffe0b2
style GenerateErrorRow fill:#ffebee
错误处理代码
1. 单型号处理错误
ErrorHandler:
If Not logger Is Nothing Then
logger.Record 0, "M09.ProcessSingleModel", "SystemError", _
"处理型号[" & modelString & "]失败: " & Err.Description, ""
End If
results.Add GenerateErrorRow(modelString, "系统错误: " & Err.Description)
Set ProcessSingleModel = results
2. 匹配错误处理
If matchResult("rowCount") = 0 Then
logger.Record 0, "M09.MatchAllMaterialTypes", "BOMMatchError", _
sheetName & " " & matchResult("message"), ""
End If
错误恢复策略
策略分类
graph TD
subgraph "错误恢复策略"
A[策略选择]
A --> B[继续处理<br/>Continue Processing]
A --> C[优雅降级<br/>Graceful Degradation]
A --> D[仅警告<br/>Warning Only]
end
subgraph "继续处理"
B1[记录错误]
B2[返回Nothing/空值]
B3[处理下一条记录]
end
subgraph "优雅降级"
C1[检测组件失败]
C2[返回错误物料]
C3[保存部分结果]
end
subgraph "仅警告"
D1[记录警告信息]
D2[继续正常流程]
D3[不中断处理]
end
B --> B1 --> B2 --> B3
C --> C1 --> C2 --> C3
D --> D1 --> D2 --> D3
style B fill:#c8e6c9
style C fill:#fff9c4
style D fill:#e1f5fe
style B3 fill:#e8f5e9
style C3 fill:#ffe0b2
style D3 fill:#e8f5e9
策略详解
1. 继续处理 (Continue Processing)
适用场景: 语法错误、系统错误、解析错误
' M03_Logic.bas
ErrorHandler:
g_Logger.Record rowIdx, "M03.ParseRule", "System Error", Err.Description, strRule
Set ParseRule = Nothing ' 返回Nothing表示失败
' 调用方检测到Nothing后继续处理下一条记录
流程:
错误发生 → 记录错误 → 返回Nothing → 调用方跳过 → 处理下一条记录
2. 优雅降级 (Graceful Degradation)
适用场景: 组件处理失败、物料提取失败
' M08_ComponentProcessor.bas
ErrorHandler:
' 返回错误物料信息而不是崩溃
Dim errorMat As Object
Set errorMat = CreateObject("Scripting.Dictionary")
errorMat("materialType") = "部件"
errorMat("materialName") = ""
errorMat("materialCode") = ""
errorMat("materialQty") = 0
errorMat("remarks") = "系统错误: " & Err.Description
流程:
错误发生 → 构造错误对象 → 返回部分信息 → 用户看到部分结果
3. 仅警告 (Warning Only)
适用场景: 映射值缺失、预处理警告
' M05_PreProcessor.bas
Else
' 记录警告但继续使用原始值
g_Logger.Record rowIdx, "M05.PreProcessor", "Mapping Warning", _
"Value not found in mapping table: " & keyName & "=" & originalValue, match.Value
End If
' 继续处理,使用原始值
流程:
检测问题 → 记录警告 → 使用原始值 → 继续正常流程
策略对比
| 策略 | 严重级别 | 结果处理 | 用户体验 | 适用场景 |
|---|---|---|---|---|
| 继续处理 | 🔴 高 | 跳过当前记录 | 部分数据缺失 | 语法/系统/解析错误 |
| 优雅降级 | 🟡 中 | 返回部分数据 | 看到错误标记 | 组件/物料提取失败 |
| 仅警告 | 🟢 低 | 使用原始值 | 无明显影响 | 映射值缺失 |
错误报告生成
clsErrorLogger.PrintReport 方法
flowchart TD
Start[PrintReport] --> CheckCount{检查错误数量}
CheckCount -->|0个错误| Exit[退出, 不生成报告]
CheckCount -->|有错误| CreateSheet[创建新工作表]
CreateSheet --> SetName[设置名称:<br/>错误报告_hhmmss]
SetName --> WriteHeader[写入表头]
WriteHeader --> FormatHeader[格式化表头:<br/>粗体+红色背景]
FormatHeader --> PrepareArray[准备输出数组]
PrepareArray --> LoopErrors[遍历错误集合]
LoopErrors --> PopulateArray[填充数组数据]
PopulateArray --> CheckEnd{还有错误?}
CheckEnd -->|是| LoopErrors
CheckEnd -->|否| WriteData[批量写入数据]
WriteData --> AutoFit[自动调整列宽]
AutoFit --> End[结束]
style CheckCount fill:#fff9c4
style Exit fill:#c8e6c9
style FormatHeader fill:#ffe0b2
style End fill:#e8f5e9
错误报告结构
graph TB
subgraph "错误报告工作表"
Header[第1行: 表头<br/>红色背景+粗体]
Data[第2行-N: 数据]
end
subgraph "列结构"
ColA[列A: 原表行号]
ColB[列B: 来源模块]
ColC[列C: 错误类型]
ColD[列D: 详细描述]
ColE[列E: 原始数据]
end
subgraph "示例数据"
Row2[<table><tr><td>125</td><td>M03.ParseAtom</td><td>SyntaxError</td><td>No = or != found</td><td>azxsA0</td></tr></table>]
Row3[<table><tr><td>138</td><td>M03.Conflict</td><td>LogicConflict</td><td>Mutually Exclusive</td><td>azxs=径向 AND azxs=下轴向</td></tr></table>]
end
Header --> ColA & ColB & ColC & ColD & ColE
Data --> Row2 & Row3
style Header fill:#ffcdd2
style Row2 fill:#fafafa
style Row3 fill:#fafafa
代码实现
Public Sub PrintReport(targetWb As Workbook)
If pErrors.count = 0 Then Exit Sub
' 1. 创建新工作表
Dim ws As Worksheet
Set ws = targetWb.Worksheets.Add(After:=targetWb.Worksheets(targetWb.Worksheets.count))
ws.Name = "错误报告_" & Format(Now, "hhmmss")
' 2. 写入表头(红色背景,粗体)
ws.Range("A1:E1").Value = Array("原表行号", "来源模块", "错误类型", "详细描述", "原始数据")
ws.Range("A1:E1").Font.Bold = True
ws.Range("A1:E1").Interior.Color = RGB(255, 200, 200)
' 3. 准备输出数组(批量写入提高性能)
Dim arrOutput() As Variant
ReDim arrOutput(1 To pErrors.count, 1 To 5)
Dim i As Long
Dim vItem As Variant
For i = 1 To pErrors.count
vItem = pErrors(i)
arrOutput(i, 1) = vItem(0) ' 行号
arrOutput(i, 2) = vItem(1) ' 来源模块
arrOutput(i, 3) = vItem(2) ' 错误类型
arrOutput(i, 4) = vItem(3) ' 描述
arrOutput(i, 5) = vItem(4) ' 上下文
Next i
' 4. 批量写入数据
ws.Range("A2").Resize(UBound(arrOutput, 1), 5).Value = arrOutput
' 5. 自动调整列宽
ws.Columns.AutoFit
End Sub
报告生成调用
' M01_Main.bas - BOM转换系统
If logger.HasErrors Then
logger.PrintReport ActiveWorkbook
MsgBox "转换完成,但发现部分数据存在逻辑冲突,已生成错误报告。", vbExclamation
End If
' M09_BOMExtractor.bas - BOM提取系统
If g_Logger.HasErrors Then
g_Logger.PrintReport ActiveWorkbook
result = "BOM提取完成,但发现部分错误,已生成错误报告。"
Else
result = "BOM提取成功完成!"
End If
最佳实践
1. 一致的日志记录器初始化
所有可能产生错误的模块都遵循相同的初始化模式:
' 模块级别声明
Private g_Logger As clsErrorLogger
' 公共初始化方法
Public Sub Init[ModuleName](logger As clsErrorLogger)
Set g_Logger = logger
End Sub
优点:
- 统一的接口
- 依赖注入模式
- 易于测试和维护
2. 结构化的错误信息
每条错误记录都包含5个关键信息:
| 字段 | 类型 | 用途 | 示例 |
|---|---|---|---|
| 行号 | Long | 定位Excel行 | 125 |
| 来源模块 | String | 定位代码位置 | "M03.ParseAtom" |
| 错误类型 | String | 错误分类 | "SyntaxError" |
| 详细描述 | String | 人类可读的描述 | "No = or != found" |
| 原始数据 | String | 调试上下文 | "azxsA0" |
3. 防御性编程
使用 Nothing 检查:
If Not g_Logger Is Nothing Then
g_Logger.Record 0, "M06.ParseProductModel", "SystemError", _
"解析过程发生错误: " & Err.Description, modelString
End If
优点: 即使日志记录器未初始化也不会崩溃
4. 延迟绑定避免依赖
' 使用 CreateObject 而不是 New
Set params = CreateObject("Scripting.Dictionary")
Set errorMat = CreateObject("Scripting.Dictionary")
优点:
- 无需添加外部引用
- 提高兼容性
- 减少部署问题
5. 批量操作优化
错误报告使用数组批量写入:
' 准备数组
ReDim arrOutput(1 To pErrors.count, 1 To 5)
' 填充数组
For i = 1 To pErrors.count
arrOutput(i, 1) = ...
Next i
' 一次性写入
ws.Range("A2").Resize(UBound(arrOutput, 1), 5).Value = arrOutput
优点: 比逐单元格写入快10-100倍
6. 用户友好的错误通知
If logger.HasErrors Then
logger.PrintReport ActiveWorkbook
MsgBox "转换完成,但发现部分数据存在逻辑冲突,已生成错误报告。", _
vbExclamation, "处理完成"
End If
要点:
- 明确告知有错误
- 说明已生成报告
- 使用合适的图标类型
7. 错误级别分类
使用统一的错误类型标识:
' 致命错误 - 红色
"SystemError"
"SyntaxError"
"ModelParseError"
' 警告 - 黄色
"LogicConflict"
"BOMMatchError"
"ValidationError"
' 信息 - 绿色
"MappingWarning"
8. 上下文信息保留
始终记录导致错误的原始数据:
g_Logger.Record rowIdx, "M03.ParseAtom", "Syntax Error", _
"No = or != found", strAtom ' 保留原始数据
优点: 便于后续调试和修复
测试覆盖
M99_TestRunner.bas 中的错误测试
graph TD
subgraph "错误测试用例"
T1[Test_LogicConflict01<br/>相等与不等冲突]
T2[Test_LogicConflict02<br/>互斥值冲突]
T3[Test_SysError01<br/>空条件处理]
T4[Test_PP_MissingValue<br/>映射值缺失]
end
subgraph "验证内容"
V1[错误被正确记录]
V2[返回Nothing/空值]
V3[处理继续不中断]
V4[错误报告正确生成]
end
T1 --> V1 & V2 & V3
T2 --> V1 & V2 & V3
T3 --> V1 & V2 & V3
T4 --> V1 & V3 & V4
style T1 fill:#ffe0b2
style T2 fill:#ffe0b2
style T3 fill:#ffcdd2
style T4 fill:#c8e6c9
测试示例
逻辑冲突测试
Public Sub Test_LogicConflict01()
' 测试: azxs=1 AND azxs!=1
Dim result As Collection
Set result = M03_Logic.ParseRule("azxs=1 AND azxs!=1", 10)
' 验证: 应该返回Nothing并记录错误
Assert result Is Nothing, "应该检测到相等与不等冲突"
End Sub
映射值缺失测试
Public Sub Test_PP_MissingValue()
' 测试: azxs值未在映射表中
Dim result As String
result = M05_PreProcessor.PreprocessCondition("azxs=INVALID", "接头", 10)
' 验证: 应该记录警告但继续处理
Assert result <> "", "即使映射缺失也应返回结果"
End Sub
快速参考
错误处理常用代码片段
1. 初始化日志记录器
' 在主模块中
Dim logger As New clsErrorLogger
' 传递给子模块
M03_Logic.InitLogic logger
M05_PreProcessor.InitPreProcessor logger, wsMapping
2. 记录错误
' 完整格式
g_Logger.Record rowIdx, "Module.Function", "ErrorType", "Description", "Context"
' 示例
g_Logger.Record 125, "M03.ParseAtom", "Syntax Error", _
"No = or != found", "azxsA0"
3. 检查并报告错误
If logger.HasErrors Then
logger.PrintReport ActiveWorkbook
MsgBox "处理完成,但发现错误。", vbExclamation
End If
4. 标准错误处理器
ErrorHandler:
If Not g_Logger Is Nothing Then
g_Logger.Record rowIdx, "Module.Function", "SystemError", _
Err.Description, contextData
End If
Set FunctionResult = Nothing
错误类型速查表
| 类型标识 | 显示名称 | 严重级别 | 通用模块 |
|---|---|---|---|
SystemError |
System Error | 🔴 高 | 所有模块 |
System Error |
System Error | 🔴 高 | M03_Logic |
SyntaxError |
Syntax Error | 🔴 高 | M03_Logic |
LogicConflict |
Logic Conflict | 🟡 中 | M03_Logic |
MappingWarning |
Mapping Warning | 🟢 低 | M05_PreProcessor |
ModelParseError |
Model Parse Error | 🔴 高 | M06_ModelParser |
BOMMatchError |
BOM Match Error | 🟡 中 | M07_BOMMatcher, M09_BOMExtractor |
ValidationError |
Validation Error | 🟡 中 | M08_ComponentProcessor |
错误报告格式
工作表名称: 错误报告_hhmmss (例如: 错误报告_143025)
列结构:
| 列 | 宽度 | 对齐 | 说明 |
|---|---|---|---|
| A | 自动 | 左对齐 | 原表行号 |
| B | 自动 | 左对齐 | 来源模块 |
| C | 自动 | 左对齐 | 错误类型 |
| D | 自动 | 左对齐 | 详细描述 |
| E | 自动 | 左对齐 | 原始数据 |
格式:
- 第1行: 粗体 + 红色背景 (RGB 255, 200, 200)
- 数据行: 默认格式
- 列宽: 自动调整
相关文档
- RunBOMExtraction_运行机制详解.md - BOM提取系统文档
- M03_Logic_Algorithm.md - 条件解析算法详解
- Test_PP_06_FullIntegration_流程详解.md - 预处理系统集成测试
- CLAUDE.md - 项目整体说明
文档版本: 1.0 最后更新: 2026-02-12 作者: Claude Code 状态: 初稿完成 审核: 待审核