{"record":{"id":"bc970462541cb72d","repo":"babalae/better-genshin-impact","slug":"error-bc9704","errorCode":null,"errorMessage":"实时任务名称不能为空","messagePattern":"实时任务名称不能为空","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Core/Script/Dependence/Dispatcher.cs","lineNumber":92,"sourceCode":"    }\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,\n            CancellationContext.Instance.Cts.Token);\n        await RunTask(soloTask, linkedCts.Token);\n    }\n\n","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Core/Script/Dependence/Dispatcher.cs#L74-L110","documentation":"ArgumentNullException thrown by Dispatcher.AddTrigger at line 92 when RealtimeTimer.Name is null or empty. RealtimeTimer has a parameterless constructor that leaves Name null (the field is `string?`); only the (string name) and (string name, dynamic config) constructors populate it. TaskTriggerDispatcher.AddTrigger keys on the name, so an empty name cannot route the trigger.","triggerScenarios":"JS does `new RealtimeTimer()` (no-arg ctor) then AddTrigger without setting .Name. Or `new RealtimeTimer('')` / `new RealtimeTimer(null)`. The (name, config) constructor was used but name was an empty string literal.","commonSituations":"Script author used the default constructor and forgot `.Name = '...'`. A variable intended to hold the name was undefined when the constructor ran.","solutions":["Always use a name-bearing constructor: `new RealtimeTimer('AutoSkip')`.","If using the no-arg ctor, set `timer.Name = '...'` before AddTrigger.","Validate the name string in JS before calling AddTrigger."],"exampleFix":"// before (JS)\nconst t = new RealtimeTimer();\ndispatcher.AddTrigger(t); // throws: Name is null\n\n// after (JS)\nconst t = new RealtimeTimer('AutoSkip');\ndispatcher.AddTrigger(t);","handlingStrategy":"validation","validationCode":"// JS side\nif (!timer.Name) throw new Error('RealtimeTimer.Name is required');\ndispatcher.AddTrigger(timer);","typeGuard":"// JS\nfunction hasTimerName(t) { return t != null && typeof t.Name === 'string' && t.Name.length > 0; }","tryCatchPattern":null,"preventionTips":["Prefer the RealtimeTimer(name) constructor over the no-arg constructor.","Never pass a freshly `new RealtimeTimer()` without setting Name.","Validate Name is a non-empty string before AddTrigger."],"tags":["script","argument-null","dispatcher","realtime-timer","validation"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}