{"record":{"id":"8597482dfe0f897c","repo":"egametang/ET","slug":"value-gettype-typeof-t","errorCode":null,"errorMessage":"不能把{value.GetType()}转换为{typeof (T)}","messagePattern":"不能把(.+?)转换为(.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.behaviortree/Scripts/Model/Share/BTEnv.cs","lineNumber":115,"sourceCode":"            if (key == null)\n            {\n                return false;\n            }\n            \n            if (!this.dict.TryGetValue(key, out object value))\n            {\n                return false;\n            }\n\n            try\n            {\n                IValue<T> iValue = (IValue<T>) value;\n                t = iValue.Value;\n                return true;\n            }\n            catch (InvalidCastException e)\n            {\n                throw new Exception($\"不能把{value.GetType()}转换为{typeof (T)}\", e);\n            }\n        }\n\n        public T GetStruct<T>(string key) where T : struct\n        {\n            if (!this.dict.TryGetValue(key, out object value))\n            {\n                throw new Exception($\"btenv not found key: {key} {typeof(T).FullName}\");\n            }\n\n            try\n            {\n                IValue<T> iValue = (IValue<T>) value;\n                return iValue.Value;\n            }\n            catch (InvalidCastException e)\n            {\n                throw new Exception($\"不能把{value.GetType()}转换为{typeof (T)}\", e);","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.behaviortree/Scripts/Model/Share/BTEnv.cs#L97-L133","documentation":"Thrown inside the catch of BTEnv.TryGetStruct<T> when the dict value stored under the key cannot be cast to IValue<T>. Structs are boxed in ValueTypeWrap<T> (an IValue<T>) at Add time; a mismatch between the T used at AddStruct and the T used at TryGetStruct produces an InvalidCastException. Note this is a 'Try' method that returns false only for null-key and missing-key — it THROWS on type mismatch, which is a common surprise.","triggerScenarios":"Calling AddStruct<int>(key, 100) then TryGetStruct<float>(key, out float v), or storing with one numeric type and reading with another (int vs long, int vs float). The stored ValueTypeWrap<Int32> is not assignable to IValue<Single>.","commonSituations":"Numeric type drift between the node that writes the struct (e.g. writing an int HP) and the node that reads it (expecting a long or float); refactor changed the generic type at one call site but not the other; copy-paste of node code with a different generic argument.","solutions":["Make the generic type argument T identical at AddStruct and TryGetStruct for the same key.","Audit all call sites for that key and align the types.","Because TryGetStruct throws on mismatch (does not return false), wrap it in try/catch or pre-check with ContainKey plus a known-type contract.","Introduce a shared constant/helper that pins the type per key to prevent drift."],"exampleFix":"// before\nenv.AddStruct<int>(\"hp\", 100);\nbool ok = env.TryGetStruct<float>(\"hp\", out float hp); // throws [41]\n\n// after\nenv.AddStruct<int>(\"hp\", 100);\nbool ok = env.TryGetStruct<int>(\"hp\", out int hp);","handlingStrategy":"type-guard","validationCode":"// No public API exposes the stored struct type; enforce a single T per key via a shared accessor.\n// Before reading, ensure AddStruct used the identical T for this key.","typeGuard":"// ValueTypeWrap<T> is internal-boxed; callers cannot inspect it directly.\n// Discipline: pair every AddStruct<T>(k) with TryGetStruct<T>(k) using the same T.\nstatic void AddHp(BTEnv env, int v) => env.AddStruct(\"hp\", v);\nstatic bool TryGetHp(BTEnv env, out int v) => env.TryGetStruct(\"hp\", out v);","tryCatchPattern":"try { env.TryGetStruct<int>(\"hp\", out int hp); }\ncatch (Exception e) when (e.Message.Contains(\"转换为\")) { /* type mismatch for key */ }","preventionTips":["Pin one generic type per key through a shared accessor helper.","Remember Try-prefixed methods throw on type mismatch — they are not exception-free.","When refactoring a struct type, update both Add and Get call sites together."],"tags":["behaviortree","btenv","type-mismatch","casting","csharp","unity","runtime"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}