6

我已经多次遇到这个设计问题,但从未找到一个杀手级的解决方案。

我想公开一个在所有者class范围内可编辑但仅对其他公共范围可读的集合。

试验一:

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

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

这样做的问题是外部代码可以将其转换回List并编辑,如下所示:

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

试验二:

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

有没有一种“完美”的方式来做到这一点?谢谢。

4

7 回答 7

7

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

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

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

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

编辑:这只适用于收益回报。以这种方式评估它是懒惰的,我不知道这对您来说是否是一个问题。

于 2012-11-08T01:30:54.457 回答
3

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

public ReadOnlyCollection<object> MyList { get { return _myList.AsReadOnly(); } }
于 2012-11-08T01:31:55.157 回答
2

List<T>实现IReadOnlyList<T>

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

    public IReadOnlyList<object> MyList => _myList;      // Read only
}
于 2020-06-26T10:08:12.957 回答
1

我通常使用并且非常喜欢的解决方案,因为它很简单,如下所示:

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

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

用 a 循环它foreach实际上更快:不到 1msSelect和 0.1 秒ReadOnlyCollection。对于ReadOnlyCollection,我使用了:

public IEnumerable<object> MyROList { get { return new ReadOnlyCollection<object>(_myList); } }
于 2012-11-08T01:45:58.487 回答
0

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

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

    public IList<object> MyList { get { return _myList.AsReadOnly(); } }
}
于 2012-11-08T04:08:06.300 回答
0

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

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

于 2012-11-08T01:33:01.017 回答
0

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

于 2012-11-08T01:59:44.287 回答