使用IEnumerable修改foreach循环内的集合Where()

时间:2016-10-26 03:02:15

标签: c#

虽然var app = require('express')(); var http = require('http').Server(app); var io = require('socket.io')(http); app.get('/', function(req, res) { res.sendfile('index.html'); }); http.listen(3000, function() { console.log('listening on *:3000'); }); io.on('connection', function (socket) { console.log('a user connected'); socket.on('disconnect', function () { console.log('user disconected'); }); socket.on('chat-message', function (message) { console.log('message: ' + message.text); }); }); 循环中的迭代器变量是不可变的,但如果我使用foreach进行修改,我可以在下面的示例中修改我的集合:

Where()

输出:

    static void Main(string[] args)
    {
        var list = new List<int> { 1, 2, 3, 4 };

        foreach (var listElement in list)
        {
            Console.WriteLine(listElement + " ");
            list = list.Where(x => x != listElement).ToList();
        }

        Console.WriteLine("Count: " + list.Count);
    }

有人可以解释一下这种行为吗?

4 个答案:

答案 0 :(得分:2)

我相信在foreach (var listElement in list)中,您将获得该list的{​​{1}}引用的枚举器。

在循环中,为list变量分配一个新实例,但循环使用的枚举器保留对原始枚举器的引用。

你不能做的是改变原始实例。即执行list.Remove(listElement),因为这会改变您尝试枚举的实际数据

如果将代码扩展到foreach循环实际执行的操作

,这可能会有所帮助
static void Main(string[] args)
{
    var list = new List<int> { 1, 2, 3, 4 };
    var enumerator = list.GetEnumerator();
    while (enumerator.MoveNext())
    {
        var listElement = enumerator.Current;
        Console.WriteLine(listElement + " ");
        list = list.Where(x => x != listElement).ToList();
    }
    enumerator.Dispose();

    Console.WriteLine("Count: " + list.Count);
}

答案 1 :(得分:2)

显示的代码从不&#34;修改集合&#34;这个短语的共同含义(添加/删除现有集合中的元素),而不是创建新集合。结果,没有&#34;集合被修改&#34;您可能期望的异常。

答案 2 :(得分:0)

实际上,由于您没有添加/删除集合中的任何项目,因此未对集合进行修改。关于list变量的引用,我同意Lee,即循环保留对原始枚举器的引用。

答案 3 :(得分:0)

因为foreach使用枚举器,并且枚举器无法更改基础集合,但可以更改集合中对象引用的任何对象。请参阅link。另外一个有趣的article值得阅读以理解行为