{"record":{"id":"26143d4b7aaade3f","repo":"babalae/better-genshin-impact","slug":"error-26143d","errorCode":null,"errorMessage":"实时任务对象不能为空","messagePattern":"实时任务对象不能为空","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Core/Script/Dependence/Dispatcher.cs","lineNumber":87,"sourceCode":"    /// 清理所有实时任务\n    /// </summary>\n    public void ClearAllTriggers()\n    {\n        TaskTriggerDispatcher.Instance().ClearTriggers();\n    }\n\n    /// <summary>\n    /// 添加实时任务,不会清理之前的任务\n    /// </summary>\n    /// <param name=\"timer\"></param>\n    /// <exception cref=\"ArgumentNullException\"></exception>\n    /// <exception cref=\"ArgumentException\"></exception>\n    public void AddTrigger(RealtimeTimer timer)\n    {\n        var realtimeTimer = timer;\n        if (realtimeTimer == null)\n        {\n            throw new ArgumentNullException(nameof(realtimeTimer), \"实时任务对象不能为空\");\n        }\n\n        if (string.IsNullOrEmpty(realtimeTimer.Name))\n        {\n            throw new ArgumentNullException(nameof(realtimeTimer.Name), \"实时任务名称不能为空\");\n        }\n\n        if (!TaskTriggerDispatcher.Instance().AddTrigger(realtimeTimer.Name, realtimeTimer.Config))\n        {\n            throw new ArgumentException($\"添加实时任务失败: {realtimeTimer.Name}\", nameof(realtimeTimer.Name));\n        }\n    }\n\n    public async Task RunTask(SoloTask soloTask, CancellationTokenSource customCts)\n    {\n        // 创建链接的取消令牌源，任何一个取消都会触发\n        CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(\n            customCts.Token,","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Core/Script/Dependence/Dispatcher.cs#L69-L105","documentation":"ArgumentNullException thrown by Dispatcher.AddTrigger at line 87 when the RealtimeTimer argument is null. Dispatcher is a ClearScript host object exposed to JS scripts; this guard fires when JS calls dispatcher.addTrigger(null)/undefined. The preceding `var realtimeTimer = timer` assignment is a no-op — the null check is what protects TaskTriggerDispatcher from receiving a null trigger.","triggerScenarios":"JS calls `dispatcher.AddTrigger(null)` or `dispatcher.AddTrigger(undefined)`. A factory function in JS returns undefined and its result is passed straight through. A conditional branch that should have built a RealtimeTimer was skipped.","commonSituations":"JS script author forgot to construct the RealtimeTimer object. A typo or wrong variable name passed undefined. A feature flag toggled off left the timer variable unset.","solutions":["Construct the timer before calling: `const t = new RealtimeTimer('AutoPick'); dispatcher.AddTrigger(t);`","Add a JS-side null check before calling AddTrigger.","Use the RealtimeTimer constructor that takes a name to guarantee a usable object."],"exampleFix":"// before (JS)\ndispatcher.AddTrigger(maybeTimer);\n\n// after (JS)\nif (!maybeTimer) { throw new Error('timer must be constructed before AddTrigger'); }\ndispatcher.AddTrigger(maybeTimer);","handlingStrategy":"validation","validationCode":"// JS side\nfunction addTriggerSafe(timer) {\n  if (timer == null) throw new Error('RealtimeTimer must be constructed before AddTrigger');\n  dispatcher.AddTrigger(timer);\n}","typeGuard":"// JS duck-type check\nfunction isRealtimeTimer(v) {\n  return v != null && typeof v === 'object' && typeof v.Name !== 'undefined';\n}","tryCatchPattern":null,"preventionTips":["Always construct RealtimeTimer via its name-bearing constructor before calling AddTrigger.","Add a JS wrapper that null-checks host objects before forwarding to the dispatcher.","Initialize timer variables at declaration, not in conditional branches."],"tags":["script","argument-null","dispatcher","realtime-timer","clearscript"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}