为什么不能在 IEnumerable 循环中修改 属性 bag (Dictionary<string, object>)
Why can't property bag (Dictionary<string, object>) be modified inside IEnumerable loop
考虑以下测试程序,其中我(ab)使用字典来包含可能具有未知字段(以及这些字段的未知类型)的文档,
using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
var docs = GetDocuments();
foreach(var doc in docs){
doc["a"] = new string[]{"Hello", "World!"};
var docInLoop = JsonConvert.SerializeObject(doc);
Console.WriteLine(docInLoop);
}
var serialized = JsonConvert.SerializeObject(docs);
Console.WriteLine("===========================================================================================");
Console.WriteLine(serialized);
Console.WriteLine("===========================================================================================");
var bar = docs.First()["a"] as string[];
Console.Write("First entry of first document is string[]?");
Console.WriteLine(bar==null? " No" : "Yes");
}
public static IEnumerable<Document> GetDocuments(){
return Enumerable.Range(0, 10).Select(i => {
var doc = new Document();
doc["a"] = new int[]{1,2,3,4,5,6};
return doc;
});
}
public class Document : Dictionary<string, object>{}
}
当 运行 时,预期是因为在 foreach
循环中我修改了文档,文档集合应该被修改。但这是输出:
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
===========================================================================================
[{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]}]
===========================================================================================
First entry of first document is string[]? No
从集合的反序列化来看,在循环中改变文档没有效果?这怎么可能?我错过了什么?我在循环中直接引用了文档对象...
I have a direct reference to the document object in the loop...
不,你不知道。您可以参考如何制作这些数据的方法!
这就是延迟执行的意义所在。
实际上第一次在这一行执行查询:
foreach(var doc in docs){
这是你第一次做饭。你用自己的配料给它调味得很好。
当您在这一行中序列化 doc
时:
var serialized = JsonConvert.SerializeObject(docs);
您基本上是在再次执行 GetDocuments
中的查询。这与您写的一样:
var serialized = JsonConvert.SerializeObject(GetDocuments());
这基本上意味着你要重新做饭。按照食谱做,不过这次和上次一样不加任何材料。然后你想知道为什么汤尝起来不像你第一次放的香料。
如果您在循环之前使用 ToList()
调用具体化结果,您将获得所需的结果:
var docs = GetDocuments().ToList();
这是一个不错的article elaborating on the traps of deferred execution
考虑以下测试程序,其中我(ab)使用字典来包含可能具有未知字段(以及这些字段的未知类型)的文档,
using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
var docs = GetDocuments();
foreach(var doc in docs){
doc["a"] = new string[]{"Hello", "World!"};
var docInLoop = JsonConvert.SerializeObject(doc);
Console.WriteLine(docInLoop);
}
var serialized = JsonConvert.SerializeObject(docs);
Console.WriteLine("===========================================================================================");
Console.WriteLine(serialized);
Console.WriteLine("===========================================================================================");
var bar = docs.First()["a"] as string[];
Console.Write("First entry of first document is string[]?");
Console.WriteLine(bar==null? " No" : "Yes");
}
public static IEnumerable<Document> GetDocuments(){
return Enumerable.Range(0, 10).Select(i => {
var doc = new Document();
doc["a"] = new int[]{1,2,3,4,5,6};
return doc;
});
}
public class Document : Dictionary<string, object>{}
}
当 运行 时,预期是因为在 foreach
循环中我修改了文档,文档集合应该被修改。但这是输出:
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
{"a":["Hello","World!"]}
===========================================================================================
[{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]},{"a":[1,2,3,4,5,6]}]
===========================================================================================
First entry of first document is string[]? No
从集合的反序列化来看,在循环中改变文档没有效果?这怎么可能?我错过了什么?我在循环中直接引用了文档对象...
I have a direct reference to the document object in the loop...
不,你不知道。您可以参考如何制作这些数据的方法! 这就是延迟执行的意义所在。
实际上第一次在这一行执行查询:
foreach(var doc in docs){
这是你第一次做饭。你用自己的配料给它调味得很好。
当您在这一行中序列化 doc
时:
var serialized = JsonConvert.SerializeObject(docs);
您基本上是在再次执行 GetDocuments
中的查询。这与您写的一样:
var serialized = JsonConvert.SerializeObject(GetDocuments());
这基本上意味着你要重新做饭。按照食谱做,不过这次和上次一样不加任何材料。然后你想知道为什么汤尝起来不像你第一次放的香料。
如果您在循环之前使用 ToList()
调用具体化结果,您将获得所需的结果:
var docs = GetDocuments().ToList();
这是一个不错的article elaborating on the traps of deferred execution