Files
XCEngine/docs/api/XCEngine/Scripting/ScriptComponent/SetScriptClass.md

75 lines
2.7 KiB
Markdown

# ScriptComponent::SetScriptClass
**命名空间**: `XCEngine::Scripting`
**类型**: `method`
**头文件**: `XCEngine/Scripting/ScriptComponent.h`
## 签名
```cpp
void SetScriptClass(
const std::string& namespaceName,
const std::string& className);
void SetScriptClass(
const std::string& assemblyName,
const std::string& namespaceName,
const std::string& className);
```
## 作用
设置当前脚本组件绑定的托管类信息。
## 重载差异
- `SetScriptClass(namespaceName, className)`
- 只修改命名空间和类名。
- 保留当前 `assemblyName`,默认场景下一般就是 `GameScripts`
- `SetScriptClass(assemblyName, namespaceName, className)`
- 同时修改程序集名、命名空间和类名。
## 当前实现行为
两个重载都遵循同一套顺序:
1. 记录调用前是否已有脚本类绑定。
2. 计算绑定字符串是否真的发生变化。
3. 先把新的程序集名 / 命名空间 / 类名写入 `ScriptComponent`
4. 如果“之前没有脚本类,设置后有脚本类”,调用 `ScriptEngine::Get().OnScriptComponentEnabled(this)`
5. 如果之前已经绑定脚本类,并且绑定字符串发生变化,调用 `ScriptEngine::Get().OnScriptComponentClassChanged(this)`
## 关键语义
- “首次绑定”走的是 `OnScriptComponentEnabled()` 路径,不是 `OnScriptComponentClassChanged()`
- “已绑定后改类”走的是显式重绑定路径。
- 如果新值和旧值完全相同,当前不会重复通知 `ScriptEngine`
- 因为新字符串是先写入再通知引擎,所以运行时收到类切换通知时,`ScriptComponent` 身上已经是新绑定。
最后这一点很重要。它意味着:
- 旧托管实例的停机确实会发生。
- 但如果停机过程里有原生侧日志或调试代码读取 `component->GetFullClassName()`,读到的会是新类名,而不是旧类名。
## 设计含义
- 当前实现把“首次绑定脚本类”视作启用事件。
- 已绑定类发生变化时,`ScriptEngine` 会停掉旧实例并按新类重新跟踪,这正是运行时重绑定的 canonical 入口。
- `SetAssemblyName()` / `SetNamespaceName()` / `SetClassName()` 这些原始 setter 不会触发同样的流程;需要真正重绑定时应走 `SetScriptClass()`
这和商业引擎里常见的“改 Inspector 脚本槽位 = 触发一次受控重绑定”是同一种设计取向。
## 真实行为依据
- `engine/src/Scripting/ScriptComponent.cpp`
- `engine/src/Scripting/ScriptEngine.cpp`
- `tests/Scripting/test_script_engine.cpp`
## 相关文档
- [ClearScriptClass](ClearScriptClass.md)
- [HasScriptClass](HasScriptClass.md)
- [ScriptEngine::OnScriptComponentClassChanged](../ScriptEngine/OnScriptComponentClassChanged.md)