【发布时间】:2015-02-23 11:37:50
【问题描述】:
ToReadOnlyCollection 扩展方法使用快捷语句实现,如果输入已经是 ReadOnlyCollection 的实例,则直接返回输入。 ToList 扩展方法不是。
纯粹出于好奇,是否有特殊原因,或者只是碰巧没有实施。我明白为什么保证ToList 将始终返回一个新实例可能很有用,但我很想知道是否还有其他原因。
【问题讨论】:
ToReadOnlyCollection 扩展方法使用快捷语句实现,如果输入已经是 ReadOnlyCollection 的实例,则直接返回输入。 ToList 扩展方法不是。
纯粹出于好奇,是否有特殊原因,或者只是碰巧没有实施。我明白为什么保证ToList 将始终返回一个新实例可能很有用,但我很想知道是否还有其他原因。
【问题讨论】:
只读集合不能被修改,因此返回相同的实例作为.ToReadOnlyCollection()的结果是完全可以接受的。
如果.ToList() 操作的结果有时会返回一个新列表,有时您不知道在更改输出列表时是否正在修改源列表。因此,出于这个原因,.ToList() 总是返回一个新实例。
【讨论】:
这是合理的。由于您可能会在此过程中稍后更改List<T>,因此您需要制作原始List<T> 的副本。
您可以考虑推迟该过程,直到您更改所创建列表的值。但请注意,您可能会先更改第一个列表。
示例:
List<String> first = new List<String>(new string[] {"foo","bar"});
List<String> second = first.ToList();
first[0] = "qux";
现在很难确保在这种情况下在更改列表之前制作了副本。此外,它会降低效率,因为每次更新值时,都应该首先检查是否有惰性副本,在这种情况下开始复制。此外,它可能导致爆发/泡沫:在修改单个值后最终完成的大量工作可能会导致巨大的延迟。想象一下,您正在运行一个服务器,人们在其中“分叉”一个流行列表。最终,该列表确实被修改了。这可能导致用户将等待几分钟,因为服务器开始为所有首先派生该列表的人制作副本。最好随着时间的推移分散计算,以使延迟的方差更小。
.ToReadOnlyCollection 的情况不同。在这种情况下,您在原始列表周围定义一个包装器。如果您修改原始列表,该更改也会反映在 只读 集合中。因此,您可以链接到上一个列表。例如:
$ csharp
Mono C# Shell, type "help;" for help
Enter statements below.
csharp> List<String> first = new List<String>(new string[] {"foo","bar"});
csharp> var sec = first.AsReadOnly();
csharp> sec
{ "foo", "bar" }
csharp> first[0] = "qux";
csharp> sec
{ "qux", "bar" }
【讨论】: