如何实现变量在特定函数内返回另一变量值?以Unity Time.deltaTime为例
实现根据调用上下文返回不同值的属性
Unity的Time.deltaTime之所以能在FixedUpdate里返回fixedDeltaTime,核心是靠上下文标记+快速判断,完全不需要反射——引擎在调用FixedUpdate前会设置一个内部标记,deltaTime的getter只需要检查这个标记就返回对应值,性能可以忽略不计。以下是两种在C#里实现这类逻辑的方案:
方案一:模拟Unity的上下文标记法(推荐)
这种方式和Unity的实现逻辑一致,通过手动管理调用上下文的标记,支持嵌套调用,性能最优:
public static class CustomTime { // 普通帧间隔 public static float DeltaTime { get; set; } // 固定帧间隔(通常设为0.02f) public static float FixedDeltaTime { get; set; } = 0.02f; // 内部标记:当前是否处于FixedUpdate调用阶段 private static bool _isInFixedUpdate; // 对外暴露的动态DeltaTime,根据上下文返回对应值 public static float CurrentDeltaTime { get => _isInFixedUpdate ? FixedDeltaTime : DeltaTime; } // 进入固定更新上下文(由框架/引擎在调用FixedUpdate前调用) public static void EnterFixedUpdateContext() => _isInFixedUpdate = true; // 退出固定更新上下文(由框架/引擎在FixedUpdate调用结束后调用) public static void ExitFixedUpdateContext() => _isInFixedUpdate = false; }
使用示例
模拟引擎调用流程,手动控制上下文:
public class MyBehaviour { public void Update() { // 不在FixedUpdate上下文,返回普通DeltaTime float dt = CustomTime.CurrentDeltaTime; Console.WriteLine($"Update DeltaTime: {dt:F4}"); } public void FixedUpdate() { CustomTime.EnterFixedUpdateContext(); // 处于FixedUpdate上下文,返回FixedDeltaTime float dt = CustomTime.CurrentDeltaTime; Console.WriteLine($"FixedUpdate DeltaTime: {dt:F4}"); // 嵌套调用也能正确识别上下文 NestedMethod(); CustomTime.ExitFixedUpdateContext(); } private void NestedMethod() { float dt = CustomTime.CurrentDeltaTime; Console.WriteLine($"Nested in FixedUpdate DeltaTime: {dt:F4}"); } }
方案二:利用[CallerMemberName]特性(编译时获取调用者)
如果不想手动管理上下文,可通过[CallerMemberName]在编译时获取调用方法的名称,无需反射,但仅支持直接调用的场景:
using System.Runtime.CompilerServices; public static class CustomTime { public static float DeltaTime { get; set; } public static float FixedDeltaTime { get; set; } = 0.02f; public static float GetCurrentDeltaTime([CallerMemberName] string callerName = "") { return callerName == nameof(FixedUpdate) ? FixedDeltaTime : DeltaTime; } }
使用示例
调用时无需传递参数,编译时自动注入调用者名称:
public class MyBehaviour { public void Update() { float dt = CustomTime.GetCurrentDeltaTime(); Console.WriteLine($"Update DeltaTime: {dt:F4}"); } public void FixedUpdate() { float dt = CustomTime.GetCurrentDeltaTime(); Console.WriteLine($"FixedUpdate DeltaTime: {dt:F4}"); } }
注意事项
- 此方案依赖方法名称,若修改
FixedUpdate的方法名,需同步调整判断逻辑; - 嵌套调用时,
callerName会是嵌套函数的名称,而非FixedUpdate,无法识别上下文。
为什么不用反射?
反射需要遍历调用栈或获取运行时方法信息,会带来显著的性能开销,完全不适合帧更新这种高频调用场景。上面两种方案要么是简单的布尔判断,要么是编译时确定的静态信息,性能都能达到极致,完全符合Unity的设计思路。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

