{"record":{"id":"a0b8633286c8631c","repo":"babalae/better-genshin-impact","slug":"error-a0b863","errorCode":null,"errorMessage":"角色养成识别：头像识别器尚未初始化。","messagePattern":"角色养成识别：头像识别器尚未初始化。","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/GameTask/CharacterDevelopment/CharacterDevelopmentTask.cs","lineNumber":255,"sourceCode":"    private readonly CharacterDevelopmentAssets _assets;\n\n    private CharacterDevelopmentState _workflowState = CharacterDevelopmentState.OpenCharacterList;\n    private AvatarGridIconRecognizer? _recognizer;\n    private int _characterIndex;\n    private CharacterSelectionTarget? _currentTarget;\n    private CharacterDevelopmentResult? _currentResult;\n    private Queue<CharacterDevelopmentCategory> _pendingCategories = new();\n    private CharacterDevelopmentCategory _currentCategory;\n    private string? _pendingElementType;\n    private string? _pendingWeaponType;\n    private List<Point> _talentPoints = [];\n    private int _talentIndex;\n    private readonly HashSet<string> _readTalentTypes = new(StringComparer.Ordinal);\n\n    protected override ILogger Logger => _logger;\n\n    private AvatarGridIconRecognizer Recognizer =>\n        _recognizer ?? throw new InvalidOperationException(\"角色养成识别：头像识别器尚未初始化。\");\n\n    private CharacterSelectionTarget CurrentTarget =>\n        _currentTarget ?? throw new InvalidOperationException(\"角色养成识别：当前角色尚未初始化。\");\n\n    private CharacterDevelopmentResult CurrentResult =>\n        _currentResult ?? throw new InvalidOperationException(\"角色养成识别：当前结果尚未初始化。\");\n\n    public CharacterDevelopmentStateMachineTask(IReadOnlyList<string> characterNames, CharacterDevelopmentCategory categories)\n    {\n        if (characterNames.Count == 0)\n        {\n            throw new ArgumentException(\"至少需要指定一个角色。\", nameof(characterNames));\n        }\n\n        if (categories == CharacterDevelopmentCategory.None)\n        {\n            throw new ArgumentException(\"至少需要指定一个读取分类。\", nameof(categories));\n        }","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/CharacterDevelopment/CharacterDevelopmentTask.cs#L237-L273","documentation":"Thrown by the `Recognizer` property getter when `_recognizer` is null. The avatar-grid icon recognizer is only created inside `Start()` (assigned at line 311) and deliberately nulled in its `finally` block (line 337), so the field is non-null only for the duration of an active state-machine run. Accessing it outside that window is treated as a usage-contract violation rather than a recoverable runtime condition.","triggerScenarios":"Calling a `[StateHandler]`/`[StateDetector]` method directly on a `CharacterDevelopmentStateMachineTask` instance without going through `Start()`, or holding a reference to the task and reading `Recognizer` after `Start` has returned/thrown.","commonSituations":"Unit tests that invoke handler methods in isolation; a subclass or extension that calls handlers manually; logic that runs in a `finally`/continuation after the recognizer has already been disposed and nulled.","solutions":["Drive the task only through `await task.Start(ct)` — it owns recognizer creation and disposal.","If you need the recognizer in a test, construct an `AvatarGridIconRecognizer` yourself and pass it to the helper methods that accept one.","Do not read `Recognizer` from cleanup/continuation code that may run after `Start` has finished."],"exampleFix":"// before\nvar task = new CharacterDevelopmentStateMachineTask(names, cats);\nvar r = task.Recognizer; // throws: not started\n\n// after\nawait task.Start(ct); // recognizer lives only inside Start","handlingStrategy":"validation","validationCode":"// Recognizer/CurrentTarget/CurrentResult are valid only inside Start();\n// do not access them outside a running state machine.\nif (task is null || !isRunning) return; // guard caller code paths","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat Start() as the single entry/exit point; never invoke handlers or read lazy properties directly.","In tests, construct AvatarGridIconRecognizer yourself and call the static/helper methods that accept it.","Do not read Recognizer/CurrentTarget/CurrentResult from finally or continuation code."],"tags":["state-machine","null-guard","lifecycle","character-development"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}