代码之家  ›  专栏  ›  技术社区  ›  Omortis

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

c#
  •  -1
  • Omortis  · 技术社区  · 7 年前

    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() returnObjData 返回对象数据 清除() 在最后一次迭代后不调用)。

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

    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);
    }
    

    加载循环工作正常,但这似乎非常昂贵,因为可能需要10秒(如果不是100秒)的数千次迭代。每次创建一个新对象似乎效率很低。

    我错过了什么 ? 是否有某种“提交”需要首先调用?

    1 回复  |  直到 7 年前
        1
  •  -1
  •   Andrew Taylor    7 年前

    看起来你需要做的是有一个临时清单和一个长期清单。。。像这样:

    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);
    }
    

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

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

    默认情况下.NET会将一个对象的一个副本存储到内存中,然后在您使用它的任何地方“引用”该对象。举下面的例子:

    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也改变了。

    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中。