C#只读访问List <>或其他集合,或ToArray()魔术

tmt*_*tmt 0 c# collections generic-collections

第一个问题是关于保护我的List不被改变(从外部删除/添加/清除等...)的方法

有我的方式:

class Foo 
{
    public int[] MyCollection
    {
        get{ return (_myCollection==null)?null:_myCollection.ToArray();
    }
    protected List<int> _myCollection;
}
Run Code Online (Sandbox Code Playgroud)

好吗?或者有更好的想法,或者可能是模式?

第二:当我用秒表测试这个解决方案时,我非常惊讶.

List -enumeration比使用强制转换时间的List.ToArray()枚举慢:

List<int> myList = new List<int>();
for (int j = 0; j < 10000; j++)
{
    myList.Add(j);
}
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10000; i++)
{
    //casting every iteration:
    var ROC = myList.ToArray();
    int count = 0;
    foreach (var a in ROC)
    {
        count += a;
    }
}
sw.Stop();
Console.WriteLine(sw.Elapsed);
Run Code Online (Sandbox Code Playgroud)

它显示我700毫秒,和

List<int> myList = new List<int>();
for (int j = 0; j < 10000; j++)
{
    myList.Add(j);
}
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10000; i++)
{
    int count = 0;
    //No casting at all
    foreach (var a in myList)
    {
        count += a;
    }
}
sw.Stop();
Console.WriteLine(sw.Elapsed);
Run Code Online (Sandbox Code Playgroud)

告诉我843毫秒......为什么会这样?

Eri*_*ert 6

首先,如果你有两个问题,那么发两个问题.我会回答你的第一个问题.

其次,对于思考如何保护列表不受突变有好处.许多人忘记了这一点并将其内部状态暴露给了呼叫者.

你可以做很多事情.

1)首先不要使用可变列表.使用不可变列表.Add不可变列表的方法返回不同的列表,而不是改变当前列表.现在BCL中有新的不可变列表类.这些在空间和时间上都非常有效.

2)使用可变列表并每次复制.你已经这样做了.问题当然是它很慢并且使用了大量内存.

3)AsReadOnly克劳迪奥建议的回归.请注意,这只是在列表周围创建一个只读的外观; 如果列表更改,则只读外观也会更改."只读"意味着:用户无法写入.这并不意味着它永远不会改变.此外,还有一个枚举问题,我将在(4)中解决:

4)让LINQ完成工作.return _myCollection.Select(x=>x);并拥有属性类型IEnumerable<int>.这有两个缺点.首先,调用者只能获得前导枚举.其次,假设调用者foreach在属性上执行操作,然后在循环内部执行更改列表的操作.这将导致异常; 在枚举列表时,您无法更改列表.如果你需要支持那个场景,那么(1)或(2)是你最好的选择; 在那些枚举将通过快照,而不是在变异列表上.