将List <t>公开为只读的最佳方法是什么?</t>

时间:2012-11-08 01:28:30

标签: c#

我多次遇到这个设计问题,从未找到杀手解决方案。

我希望公开一个可在所有者class范围内编辑的集合,但只能读取其他公共范围。

试用1:

public class MyClass
{
    private List<object> _myList = new List<object>();

    public IEnumerable<object> MyList { get { return _myList; } }
}

问题是外部代码可以将其强制转换回List并进行编辑,如下所示:

var x = ((List<object>)MyList);

试用2:

public class MyClass
{
    private List<object> _myList = new List<object>();

    public IEnumerable<object> MyList { get { return _myList.ToList(); } }
}

这样我们就可以防止外部修改,但会多次复制List会产生不必要的开销。

试用3:

public class MyClass
{
    private List<object> _myList = new List<object>();
    private ReadOnlyCollection<object> _roList = 
        new ReadOnlyCollection<object>(_myList)

    public IEnumerable<object> MyList { get { return _roList; } }
}

这是我目前使用的标准解决方案,但ReadOnlyCollection慢了约30%:

Debug Trace:
Use normal foreach on the ReadOnlyCollection
Speed(ms): 2520,3203125
Result: 4999999950000000

use<list>.ForEach
Speed(ms): 1446,1796875
Result: 4999999950000000

Use normal foreach on the List
Speed(ms): 1891,2421875
Result: 4999999950000000

是否有完美的&#39;这样做的方式?感谢。

7 个答案:

答案 0 :(得分:6)

您是否尝试过返回枚举器?

public class MyClass
{
    private List<object> _myList = new List<object>();

    public IEnumerable<object> MyList { get { yield return _myList.GetEnumerator(); } }
}

这不会创建副本,只读,并且不能转换回列表。

修改:这仅适用于 yield 返回。以这种方式进行懒惰评估,我不知道这是否是一个问题。

答案 1 :(得分:3)

您可以使用List<T>.AsReadOnly方法公开列表的精简只读包装。将不会有额外的复制,并且调用者将立即“看到”对方法内部完成的原始数组的更改:

public ReadOnlyCollection<object> MyList { get { return _myList.AsReadOnly(); } }

答案 2 :(得分:1)

我经常使用的解决方案很多,因为它很简单,如下所示:

public IEnumerable<object> MyList { get { return _myList.Select(x => x); } }

但是,它要求您使用支持Linq的.NET版本

使用foreach进行循环时,它实际上更快:Select小于1毫秒,ReadOnlyCollection小于0.1秒。对于ReadOnlyCollection,我使用了:

public IEnumerable<object> MyROList { get { return new ReadOnlyCollection<object>(_myList); } }

答案 3 :(得分:1)

v实现List<T>

IReadOnlyList<T>

答案 4 :(得分:0)

使用ReadOnlyCollection<T>作为包装器 - 它在内部使用您的List<T>集合(使用相同的引用,因此它不会复制任何内容,对List的任何更改也会反映在ReadOnlyCollection中)。

它比提供IEnumerable属性更好,因为它还提供索引和计数信息。

答案 5 :(得分:0)

.NET Framework 4.5引入了两个新接口:IReadOnlyCollection<T>IReadOnlyList<T>List<T>实现了两个接口。

答案 6 :(得分:0)

为什么不使用List<T>.AsReadOnly method,请参阅下面的代码段:

public class MyClass
{
    private List<object> _myList = new List<object>();

    public IList<object> MyList { get { return _myList.AsReadOnly(); } }
}