{"record":{"id":"5eb516507364a6c2","repo":"babalae/better-genshin-impact","slug":"name-5eb516","errorCode":null,"errorMessage":"变量 {name} 存在循环引用","messagePattern":"变量 (.+?) 存在循环引用","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Core/Recognition/RecognitionObjectJsonLoader.cs","lineNumber":415,"sourceCode":"\n            return parameters;\n        }\n\n        private double ResolveVariable(string name)\n        {\n            if (_resolvedVars.TryGetValue(name, out var resolvedValue))\n            {\n                return resolvedValue;\n            }\n\n            if (!_config.Vars.TryGetValue(name, out var expression))\n            {\n                throw new KeyNotFoundException($\"未找到变量 {name}\");\n            }\n\n            if (!_resolvingVars.Add(name))\n            {\n                throw new InvalidOperationException($\"变量 {name} 存在循环引用\");\n            }\n\n            try\n            {\n                var value = ToDouble(EvaluateValue(expression, name));\n                _resolvedVars[name] = value;\n                return value;\n            }\n            finally\n            {\n                _resolvingVars.Remove(name);\n            }\n        }\n\n        private string NormalizeExpression(string expression)\n        {\n            var normalized = expression;\n            var parameterNames = GetParameterNames()","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Core/Recognition/RecognitionObjectJsonLoader.cs#L397-L433","documentation":"ResolveVariable uses a _resolvingVars HashSet to track the in-progress resolution chain. If adding the current name fails, a cycle is detected (var A depends on var B which depends back on var A), and InvalidOperationException is thrown to prevent infinite recursion.","triggerScenarios":"vars declares mutually referencing variables, e.g. { \"a\": \"b + 1\", \"b\": \"a + 1\" }, or a self-reference like { \"a\": \"a + 1\" }.","commonSituations":"Two vars accidentally reference each other; a var self-references during a refactor; copy-paste of an expression that points back at itself.","solutions":["Break the cycle by making at least one variable independent (a constant or expression of builtins only).","Re-express one var in terms of cw/ch/cx/cy/s rather than another var.","Run a cycle check over the vars graph during config validation."],"exampleFix":"// before\n// \"vars\": { \"a\": \"b + 1\", \"b\": \"a + 1\" }  -> cycle -> throws\n\n// after\n// \"vars\": { \"a\": \"b + 1\", \"b\": \"cw * 0.1\" }","handlingStrategy":"validation","validationCode":"static void AssertNoVarCycles(RecognitionObjectJsonFile config)\n{\n    var deps = config.Vars.ToDictionary(\n        kv => kv.Key,\n        kv => System.Text.RegularExpressions.Regex.Matches(kv.Value, \"[A-Za-z_][A-Za-z0-9_]*\")\n            .Select(m => m.Value).Where(v => config.Vars.ContainsKey(v)).ToHashSet());\n    var seen = new HashSet<string>();\n    bool Dfs(string n, HashSet<string> stack)\n    {\n        if (stack.Contains(n)) return true;\n        if (!seen.Add(n)) return false;\n        stack.Add(n);\n        foreach (var d in deps[n]) if (Dfs(d, stack)) return true;\n        stack.Remove(n);\n        return false;\n    }\n    foreach (var n in config.Vars.Keys)\n        if (Dfs(n, new())) throw new InvalidOperationException($\"Cycle detected in vars involving '{n}'.\");\n}","typeGuard":null,"tryCatchPattern":"try { return RecognitionObjectJsonLoader.Load(config, objectName, context); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"循环引用\"))\n{ Logger.LogError(ex, \"Circular var reference in Recognition.json.\"); throw; }","preventionTips":["Express each var in terms of constants or builtins; avoid var-to-var chains.","Run a cycle check over the vars graph during config validation/CI.","Review var edits that introduce new cross-references."],"tags":["config","vars","cycle","ncalc","validation"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}