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

LMB*_*LMB 6 c#

我多次遇到这个设计问题,从来没有找到杀手解决方案.

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

试验1:

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

    public IEnumerable<object> MyList { get { return _myList; } }
}
Run Code Online (Sandbox Code Playgroud)

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

var x = ((List<object>)MyList);
Run Code Online (Sandbox Code Playgroud)

试验2:

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

    public IEnumerable<object> MyList { get { return _myList.ToList(); } }
}
Run Code Online (Sandbox Code Playgroud)

这样我们就可以防止外部修改,但会造成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; } }
}
Run Code Online (Sandbox Code Playgroud)

这是我目前使用的标准解决方案,但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
Run Code Online (Sandbox Code Playgroud)

这样做有"完美"的方法吗?谢谢.

Pau*_*ips 6

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

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

    public IEnumerable<object> MyList { get { yield return _myList.GetEnumerator(); } }
}
Run Code Online (Sandbox Code Playgroud)

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

编辑:这仅适用于收益率返回.这是懒惰的评估,我不知道这是否是一个问题.


das*_*ght 5

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

public ReadOnlyCollection<object> MyList { get { return _myList.AsReadOnly(); } }
Run Code Online (Sandbox Code Playgroud)