NET 4.6引入了AsyncLocal<T>类,用于沿着异步控制流流动环境数据.我之前已经使用CallContext.LogicalGet/SetData实现了这个目的,我想知道这两者在语义上是否以及在哪些方面是不同的(除了明显的API差异,比如强类型和不依赖字符串键).

推荐答案

语义基本相同.两者都存储在ExecutionContext中,并通过异步调用流动.

区别在于API更改(正如您所描述的)以及为值更改注册回调的能力.

从技术上讲,实现上有很大的不同,因为每次复制CallContext时(使用CallContext.Clone)都会克隆CallContext,而AsyncLocal的数据保存在ExecutionContext._localValues字典中,只复制引用,不需要任何额外的工作.

为了确保当您更改AsyncLocal的值时,更新只影响当前流,将创建一个新字典,并将所有现有值浅复制到新的字典中.

这种差异对性能可能是好的,也可能是坏的,这取决于AsyncLocal的使用位置.

现在,正如Hans Passant在 comments 中提到的,CallContext最初用于远程处理,在不支持远程处理的地方(例如Net Core)不可用,这可能就是为什么将AsyncLocal添加到框架中:

#if FEATURE_REMOTING
    public LogicalCallContext.Reader LogicalCallContext 
    {
        [SecurityCritical]
        get { return new LogicalCallContext.Reader(IsNull ? null : m_ec.LogicalCallContext); } 
    }

    public IllogicalCallContext.Reader IllogicalCallContext 
    {
        [SecurityCritical]
        get { return new IllogicalCallContext.Reader(IsNull ? null : m_ec.IllogicalCallContext); } 
    }
#endif

注意:VisualStudioSDK中还有一个AsyncLocal,基本上是CallContext的包装,它显示了这些概念的相似性:Microsoft.VisualStudio.Threading.

.net相关问答推荐

.NET Blazor-使用子组件中的处理程序方法进行双向数据绑定

ASP.NET核心最小API必须以正斜杠开头吗?

无法使用 int.Parse 从字符串转换值

从 byte[] 创建 zip 文件

在 .NET 反射中使用 GetProperties() 和 BindingFlags.DeclaredOnly

每 X 秒执行一次指定函数

为什么循环引用被认为是有害的?

ILMerge 最佳实践

日期时间是什么意思?在 C# 中是什么意思?

操作对事务的状态无效错误和事务范围

所有数组在 C# 中都实现了哪些接口?

如何将 XPath 与 XElement 或 LINQ 一起使用?

如何在多个解决方案之间共享相同的 Resharper 设置,无需人工干预?

将两个列表映射到 C# 中的字典中

更改 SqlConnection 超时

内存分配:堆栈与堆?

如何从 HashSet 中检索实际项目?

如何为我的 C# 应用程序创建产品密钥?

在 C#/.NET 中合并两个图像

MultipleActiveResultSets=True 还是多个连接?