.NET 6中IConfiguration读取IReadOnlyCollection返回默认值原因咨询
核心逻辑:配置绑定对集合类型的差异化处理
.NET 6的配置绑定系统(ConfigurationBinder.Get方法)在处理集合类型时,会根据目标集合的可修改性和是否存在默认实例来决定行为,这就是你遇到问题的根源:
IReadOnlyCollection
+ 非null默认值的情况 IReadOnlyCollection<string>是只读接口,没有暴露任何添加、修改或清空元素的方法。当你的SomeColl属性有非null的默认集合实例时,配置绑定系统无法修改这个已存在的只读集合内容,只能直接复用这个默认实例,因此你读取到的是默认值"wrongString",而非配置文件中的值。IReadOnlyCollection
+ 默认值为null!的情况
当默认值设为null!时,绑定系统发现目标实例为null,会自动创建一个可写的集合实现(比如List<string>,它同时实现了IReadOnlyCollection<string>),然后将配置文件中的"expectedString"填充到这个新集合里,最终就能正确读取到配置值。ICollection
的情况 ICollection<string>是可修改接口,支持清空、添加元素等操作。不管你是否设置了默认集合实例,绑定系统都会先清空现有集合(如果存在),再将配置文件中的元素加载进去,所以最终得到的是配置里的"expectedString",覆盖了默认值。
补充说明
配置绑定的这种设计是为了贴合集合接口的语义:只读集合本就不应该被修改,所以绑定系统不会尝试去修改已存在的只读集合实例;而可写集合则允许修改,因此绑定系统会直接操作现有实例来填充配置数据。
// 问题复现的记录定义 public record SomeOptions { public IReadOnlyCollection<string> SomeColl { get; init; } = new List<string> { "wrongString" }; } // 修复方案1:默认值设为null! public record SomeOptions { public IReadOnlyCollection<string> SomeColl { get; init; } = null!; } // 修复方案2:改用可写集合类型 public record SomeOptions { public ICollection<string> SomeColl { get; init; } = new List<string> { "wrongString" }; }
内容的提问来源于stack exchange,提问作者VladOhotnikov

