{"record":{"id":"9db18d3231bb0096","repo":"EllanJiang/GameFramework","slug":"serialize-callback-is-invalid","errorCode":null,"errorMessage":"Serialize callback is invalid.","messagePattern":"Serialize callback is invalid\\.","errorType":"exception","errorClass":"GameFrameworkException","httpStatus":null,"severity":"error","filePath":"GameFramework/Base/GameFrameworkSerializer.cs","lineNumber":68,"sourceCode":"        /// <summary>\n        /// 尝试从指定流获取指定键的值回调函数。\n        /// </summary>\n        /// <param name=\"stream\">指定流。</param>\n        /// <param name=\"key\">指定键。</param>\n        /// <param name=\"value\">指定键的值。</param>\n        /// <returns>是否从指定流获取指定键的值成功。</returns>\n        public delegate bool TryGetValueCallback(Stream stream, string key, out object value);\n\n        /// <summary>\n        /// 注册序列化回调函数。\n        /// </summary>\n        /// <param name=\"version\">序列化回调函数的版本。</param>\n        /// <param name=\"callback\">序列化回调函数。</param>\n        public void RegisterSerializeCallback(byte version, SerializeCallback callback)\n        {\n            if (callback == null)\n            {\n                throw new GameFrameworkException(\"Serialize callback is invalid.\");\n            }\n\n            m_SerializeCallbacks[version] = callback;\n            if (version > m_LatestSerializeCallbackVersion)\n            {\n                m_LatestSerializeCallbackVersion = version;\n            }\n        }\n\n        /// <summary>\n        /// 注册反序列化回调函数。\n        /// </summary>\n        /// <param name=\"version\">反序列化回调函数的版本。</param>\n        /// <param name=\"callback\">反序列化回调函数。</param>\n        public void RegisterDeserializeCallback(byte version, DeserializeCallback callback)\n        {\n            if (callback == null)\n            {","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/EllanJiang/GameFramework/blob/d0c010b05167c58e92350449d04864a91ca13fd2/GameFramework/Base/GameFrameworkSerializer.cs#L50-L86","documentation":"GameFrameworkSerializer<T> stores per-version serialize callbacks used when writing data to a stream. RegisterSerializeCallback requires an actual delegate; it throws when the callback parameter is null because a null entry would cause a NullReferenceException later during Serialize.","triggerScenarios":"Calling serializer.RegisterSerializeCallback(version, null), often due to a typo'd method group, a conditional that resolved to null, or a delegate field that was never assigned.","commonSituations":"Passing a method name that doesn't exist/compile to a cast delegate, registering callbacks from config where the target object was destroyed (Unity), or copy-paste errors leaving one registration with a null delegate.","solutions":["Pass a valid non-null SerializeCallback delegate (e.g. a static/instance method or lambda) for the version.","Verify the delegate expression actually resolves (no null-returning factory) before registering.","Ensure the object owning the callback method is alive in Unity (not destroyed) when registering.","Guard registration with a null check on the callback and log/skip if null."],"exampleFix":"// before\nserializer.RegisterSerializeCallback(1, null);\n// after\nserializer.RegisterSerializeCallback(1, (stream, data) =>\n{\n    stream.Write(BitConverter.GetBytes(data.Id), 0, sizeof(int));\n    return true;\n});","handlingStrategy":"validation","validationCode":"if (callback == null) { throw new InvalidOperationException(\"Serialize callback required.\"); }\nserializer.RegisterSerializeCallback(version, callback);","typeGuard":"static bool IsValidCallback(GameFrameworkSerializer<T>.SerializeCallback cb) => cb != null;","tryCatchPattern":"try { serializer.RegisterSerializeCallback(version, callback); } catch (GameFrameworkException) { /* log null callback registration attempt */ }","preventionTips":["Never pass method groups that may fail to bind","Assert callbacks are non-null in tests for each registered version","Centralize registrations in one setup method"],"tags":["csharp","null-argument","serialization","callback"],"backgroundTag":"null-argument","analyzedSha":"d0c010b05167c58e92350449d04864a91ca13fd2","analyzedAt":"2026-09-15T13:37:15.352Z","contentChangedAt":"2026-09-15T13:37:15.352Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}