C#中HttpRequestMessage只读Headers为何两种赋值表现不同?
现象成因说明
HttpRequestMessage.Headers确实是仅暴露get访问器的只读属性,两种写法表现不一致的核心原因是:Headers = {}根本不是对Headers属性的赋值操作,而是C#的集合初始化器语法糖,编译器对它的处理逻辑和直接赋值完全不同。
两种写法的编译器处理差异
- 写
Headers = default/Headers = null/Headers = 某HttpRequestHeaders实例时,属于对象初始化器中的标准属性赋值逻辑,编译器会生成调用Headers属性set访问器的代码,因为该属性没有公开set访问器,自然会触发“只读属性不可赋值”的编译错误,这个表现完全符合C#的属性访问规则。 - 写
Headers = {}时,编译器不会尝试调用Headers属性的set访问器:它会先通过get访问器拿到对象构造时已经初始化好的HttpRequestHeaders集合实例(HttpRequestMessage无参构造执行时就会为Headers属性分配好实例,永远不会为null),再按照大括号内的内容执行集合元素添加操作——空大括号代表不添加任何元素,全程只调用了属性的get访问器,没有任何赋值行为,自然不会触发只读报错。
编译等价代码示例
你写的空集合初始化代码:
var request = new HttpRequestMessage() { Headers = {} };
编译后等价于以下逻辑,全程没有对Headers属性赋值:
var request = new HttpRequestMessage(); var headersInstance = request.Headers; // 仅调用get拿到已有实例 // 大括号为空,不执行任何Add操作
如果大括号内写了集合元素,比如:
var request = new HttpRequestMessage() { Headers = { {"User-Agent", "TestClient"} } };
编译后会在拿到集合实例后,自动调用对应Add方法添加元素,同样不会给属性本身赋值:
var request = new HttpRequestMessage(); var headersInstance = request.Headers; headersInstance.Add("User-Agent", "TestClient");
注意:如果写
Headers = new HttpRequestHeaders(),就属于真正的属性赋值操作,同样会触发只读属性不可赋值的编译错误,和空大括号的逻辑有本质区别。
内容的提问来源于stack exchange,提问作者AnGG
相关产品推荐
相关产品推荐

