通过直通回调参数传递状态或通过闭包捕获状态是否有技术原因?

Is there a technical reason to pass state via a pass-thru callback argument, or capture it via a closure?

昨晚在审查代码时,我发现了这段代码。值得注意的是,state 是通过执行泛型回调操作的 lambda 捕获的。

public static void Post<TState>(TState state, Action<TState> callback){

    if(SynchronizationContext.Current is SynchronizationContext currentContext)
        // Use capture-semantics for state
        currentContext.Post(_ => callback(state), null);
    else{
        callback(state);
    }
}

Post 然而,原生支持state的pass-thru,所以上面也可以改写成这样...

public static void Post<TState>(TState state, Action<TState> callback){

    if(SynchronizationContext.Current is SynchronizationContext currentContext)
        // Use pass-thru state, not 'capture'
        currentContext.Post(passedBackState => callback((TState)passedBackState), state);
    else{
        callback(state);
    }
}

我的问题很简单...在这个特定的用例中,回调定义在与需要传递给它的状态相同的范围内,是否有任何 技术 使用捕获语义(第一个)而不是直通(第二个)的好处 and/or 缺点?我个人喜欢第一个,因为只有一个变量,但我问的是 技术上的 差异,如果两者似乎都有效的话。

闭包在堆上分配一个需要进行垃圾回收的新对象。通过状态参数传递数据不分配(除非数据是需要装箱的值类型)。

这些分配会叠加在频繁使用的方​​法或长期存在的进程(如 Web 应用程序)上,导致垃圾处理和延迟的 CPU 周期浪费。积极删除此类分配是 .NET Core 比 .NET Old 快得多的原因之一。

Roslyn Heap Allocation Analyzer 这样的 Roslyn 分析器突出显示了诸如装箱值类型、闭包、使用 params 数组等隐式分配。

更新

Rider 的 Dynamic Program Analysis 还突出显示了由于闭包、装箱、枚举器等引起的分配