You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现变量在特定函数内返回另一变量值?以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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 10:20:32