{"record":{"id":"185890b5d36ea2d0","repo":"babalae/better-genshin-impact","slug":"fieldname","errorCode":null,"errorMessage":"{fieldName} 不能为空","messagePattern":"\\{fieldName\\} 不能为空","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Core/Recognition/RecognitionObjectJsonLoader.cs","lineNumber":498,"sourceCode":"        }\n\n        private static Scalar BuildScalar(IReadOnlyList<double> values, string fieldName)\n        {\n            return values.Count switch\n            {\n                1 => new Scalar(values[0]),\n                2 => new Scalar(values[0], values[1]),\n                3 => new Scalar(values[0], values[1], values[2]),\n                4 => new Scalar(values[0], values[1], values[2], values[3]),\n                _ => throw new InvalidOperationException($\"{fieldName} 必须是 1 到 4 个数字\"),\n            };\n        }\n\n        private static TEnum ParseEnumExact<TEnum>(string? value, string fieldName) where TEnum : struct, Enum\n        {\n            if (string.IsNullOrWhiteSpace(value))\n            {\n                throw new InvalidOperationException($\"{fieldName} 不能为空\");\n            }\n\n            if (Enum.TryParse<TEnum>(value, false, out var parsed))\n            {\n                return parsed;\n            }\n\n            throw new InvalidOperationException($\"{fieldName} 的值 {value} 不是有效的 {typeof(TEnum).Name}\");\n        }\n\n        private static Color ParseColor(string value)\n        {\n            return ColorTranslator.FromHtml(value);\n        }\n\n        private static double ToDouble(object? value)\n        {\n            return value switch","sourceCodeStart":480,"sourceCodeEnd":516,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Core/Recognition/RecognitionObjectJsonLoader.cs#L480-L516","documentation":"ParseEnumExact rejects null or whitespace for fields parsed as enums. The always-required type field goes through it unconditionally, and conditional fields (templateMatchMode, colorCode, ocrEngine, anchor, templateMode) pass through it when present. InvalidOperationException signals the field must have a value.","triggerScenarios":"A RecognitionObject omits type entirely or sets it to an empty string; or a present-but-blank enum field (e.g. \"ocrEngine\": \"\") reaches ParseEnumExact.","commonSituations":"Required type field removed; field left blank during editing; conditional enum field present as empty string instead of being omitted.","solutions":["Provide a valid enum value, e.g. \"type\": \"TemplateMatch\".","Omit optional enum fields entirely rather than leaving them blank.","Validate that required enum fields are non-empty before runtime."],"exampleFix":"// before\n// { }                       // no type -> throws\n// { \"type\": \"\" }            // blank type -> throws\n\n// after\n// { \"type\": \"TemplateMatch\" }","handlingStrategy":"validation","validationCode":"foreach (var (name, cfg) in config.Objects)\n{\n    if (string.IsNullOrWhiteSpace(cfg.Type))\n        throw new InvalidOperationException($\"Object '{name}' is missing required 'type'.\");\n}\n// also ensure present optional enum fields are not blank:\nforeach (var (name, cfg) in config.Objects)\n{\n    if (cfg.OcrEngine is \"\" or null && cfg.OcrEngine is not null)\n        throw new InvalidOperationException($\"Object '{name}' has blank ocrEngine; omit it instead.\");\n}","typeGuard":null,"tryCatchPattern":"try { return RecognitionObjectJsonLoader.Load(config, objectName, context); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"不能为空\"))\n{ Logger.LogError(ex, \"A required enum field is blank.\"); throw; }","preventionTips":["Make 'type' mandatory in your JSON schema/authoring tool.","Omit optional enum fields rather than leaving them as empty strings.","Add a CI check that flags blank enum fields."],"tags":["config","enum","validation","recognition"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}