哪种方式返回List<T>的只读包装器更可取?

10

假设我们有一个带有私有List的通用类。 我们可以通过至少两种方式使其返回此列表的只读包装:

public class Test<T>
{
    public List<T> list = new List<T>();

    public IEnumerable<T> Values1
    {
        get
        {
            foreach (T i in list)
                yield return i;
        }
    }

    public IEnumerable<T> Values2
    {
        get
        {
            return list.AsReadOnly();
        }
    }
}

Values1Values2都反映了基础集合中的任何更改,并通过它们自己防止其修改。

哪种方式更可取?有什么需要注意的事项吗?还是有其他更好的方法吗?


1
你也可以使用Linq的return list.Select(x => x); - Guillaume
1个回答

12

如果只需要输出一个 IEnumerable<T>,我更喜欢使用:

public IEnumerable<T> Values
{
    return this.list.AsReadOnly();
}

由于 ReadOnlyCollection<T> 实现了 IEnumerable<T>,因此它可以为您的对象提供安全的封装,同时还具有灵活性和高效性,并防止强制转换能够设置值。

如果您决定在结果中执行其他操作,则始终可以稍后更改内部实现。


1
我赞同Reed的观点 - ReadOnly集合的构建实际上只是包装现有列表,因此它是一个非常廉价的调用;它实现了IEnumerable<T>,因此在那里完全兼容;它实现了ICollection<T>,因此您可以快速访问Count。总体而言,这是个好东西! - JerKimball
防止强制转换能够设置值。在第一种情况下,将getter的结果进行强制转换不应该使得添加/删除原始列表中的值成为可能吧?因为你无论如何都应该使用原始列表的副本进行操作,或者我误解了你的意思? - Guillaume
如果使用test.Values1.ToList()生成的列表,那么它肯定是一个副本。 - horgh
在这种情况下,“yield return”和“AsReadOnly()”的结果也是类似的。 - horgh
是的。在所有情况下,结果都是相似的。yield return 会生成一个新的(编译器生成的)类型。AsReadOnly 使用一个框架类型。虽然这都是实现细节,但这是我的偏好。 - Reed Copsey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接