List / Dictionary .Clear()方法的奇怪行为

时间:2018-06-28 19:27:11

标签: c#

我有一个与此类似的代码块:

spark.sql("SELECT udafName(V) as aggV FROM data")

但是,List<Object> returnObjDataLine = new List<object>(); foreach (var tuple in dataPerTime) { returnObjDataLine.Clear(); returnObjDataLine.Add(tuple.Item1); foreach (var line in PlotLines) { if (tuple.Item2.Equals(line.Key)) { returnObjDataLine.Add(tuple.Item3); } else { returnObjDataLine.Add(null); } } returnObjData.Add(returnObjDataLine); } 方法会清除已经添加到Clear()字典中的数据。如果有10,000个元组,则循环运行之后,returnObjData将包含10,000个添加的最后一个数据片段的实例(returnObjData在最后一次迭代之后不被调用)。

如果我修改代码以在每次迭代中创建一个新列表:

Clear()

加载循环可以正常工作,但是这看起来非常昂贵,因为如果不需要十万次迭代,则可能需要十秒。每次创建一个新对象似乎效率低下。

foreach (var tuple in dataPerTime) { List<Object> returnObjDataLine = new List<object>(); returnObjDataLine.Add(tuple.Item1); foreach (var line in PlotLines) { if (tuple.Item2.Equals(line.Key)) { returnObjDataLine.Add(tuple.Item3); } else { returnObjDataLine.Add(null); } } returnObjData.Add(returnObjDataLine); } 我缺少什么?是否需要先调用某种“提交”?

1 个答案:

答案 0 :(得分:-1)

看起来您需要做的是拥有一个临时列表和一个长期列表...类似这样的东西:

List<Object> longTermObjects = new List<object>();

foreach (var tuple in dataPerTime)
{
    List<Object> returnObjDataLine = new List<Object>();
    returnObjDataLine.Add(tuple.Item1);
    foreach (var line in PlotLines)
    {
        if (tuple.Item2.Equals(line.Key))
        {
            returnObjDataLine.Add(tuple.Item3);
        }
        else
        {
            returnObjDataLine.Add(null);
        }
    }
    longTermObjects.Add(returnObjDataLine);
}

这将为您在每次迭代时提供一个干净的returnObjDataLine,而不会删除longTermObjects中的引用项。

编辑以添加引用类型信息:

默认情况下,.NET将对象的1个副本存储到内存中,然后在您使用该对象的任何位置“引用”该对象。请看以下示例:

int A = 1;
int B = A;
Console.WriteLine($"A = {A}");
Console.WriteLine($"B = {B}");
A = 0;
Console.WriteLine($"A = {A}");
Console.WriteLine($"B = {B}");

结果:

A = 1
B = 1
A = 0
B = 0

为什么要问第四行的B = 0?因为B引用了A,所以它不包含A的实际值,所以当A更改时,B也随之更改。

如果我希望B仅包含A的值,则需要一种方法来创建新的“值”而不是引用。每种对象类型的执行方式不同。一种方法,可能不是最好的方法,例如:

int B = int.Parse(A.ToString());

将A转换为表示A的值的字符串,然后使用Parse将其转换为新的int。现在,我将值存储在B中,而不仅仅是引用。

如果我想对一个对象表做同样的事情,那么我将不得不做这样的事情:

List<MyObject> oldList = new List<MyObject>();
//Put some objects into oldList

List<MyObject> newList = oldList.Select(x => new MyObject(x.Param1, x.Param2)).ToList();

在此示例中,我基本上是将每个对象放在oldList中,并创建一个新的MyObject,然后将其放入newList中。