C#编译器是否会优化表达式体成员重复求值?如何复用集合实例?
编译器会优化为单实例吗?
不会。你的理解完全正确——表达式体属性(=>)每次被访问时,都会执行右侧的表达式。不管是用new() { ... }初始化列表,还是用集合表达式[...],每次访问Names都会创建一个全新的List<string>实例。C#编译器不会做“复用实例”的优化,因为这会改变代码语义(比如外部修改返回列表时,不同访问拿到的实例状态会不一致,编译器不会擅自假设你不需要这种行为)。
集合表达式和new()初始化有区别吗?
没有本质区别。集合表达式是C# 10+引入的语法糖,针对List<string>场景,编译器会把[...]编译成和new List<string> { ... }几乎一致的代码——同样是每次执行时创建新列表实例、填充元素后返回。两种写法在实例创建的行为上完全相同。
如何实现只返回一个实例?
要避免每次访问都创建新实例,需要把列表实例提前初始化并存储,让属性直接返回这个预创建的实例。常见方案有以下几种:
1. 用只读字段存储实例,属性返回该字段
这是最简单的方案,适用于允许外部修改集合内容的场景:
private readonly List<string> _names = new() { "Foo", "Bar", "Baz" }; public List<string> Names => _names;
注意:如果外部代码调用Names.Add("Qux"),会直接修改内部的_names集合,因为返回的是同一个实例的引用。
2. 返回不可变集合(推荐)
如果不想让外部修改集合内容,可以使用.NET的不可变集合类型(比如ImmutableList<T>):
using System.Collections.Immutable; private readonly ImmutableList<string> _names = ImmutableList.Create("Foo", "Bar", "Baz"); public ImmutableList<string> Names => _names;
也可以用集合表达式简化初始化:
using System.Collections.Immutable; private readonly ImmutableList<string> _names = ["Foo", "Bar", "Baz"].ToImmutableList(); public ImmutableList<string> Names => _names;
不可变集合的所有修改操作都会返回新实例,不会影响原集合,安全性更高。
3. 返回只读包装器
如果必须返回List<string>或IReadOnlyList<T>,同时防止外部修改集合,可以用AsReadOnly()方法返回只读包装:
private readonly List<string> _names = new() { "Foo", "Bar", "Baz" }; public IReadOnlyList<string> Names => _names.AsReadOnly();
这样外部只能读取集合元素,无法执行添加、删除等修改操作(调用修改方法会抛出NotSupportedException)。
内容的提问来源于stack exchange,提问作者Jez

