【问题标题】:The argument (list<T>) in my method will be changed我的方法中的参数 (list<T>) 将被更改
【发布时间】:2017-01-18 11:33:29
【问题描述】:

我将对象列表List&lt;solutions&gt;“_solutions”作为参数发送到方法,然后将此参数复制到另一个名为“SOLUTIONS”的列表,并对 SOLUTIONS 进行一些更改,最后返回 SOLUTIONS .但是当我更改解决方案时,_solution 将被更改。我不想更改_solutions。 例如在SOLUTIONS[pp].Route.Clear(); 行之后,当 pp=0 时,_solution[0].Route 将被清除。

static List<solutions> CrossOverB(List<solutions> _Solutions)
{
    List<solutions> SOLUTIONS = new List<solutions>();
    SOLUTIONS.AddRange(_Solutions);

    int pp = 0;
    List<int> Team1;
    List<int> Team2;

    List<int> TempOff1;
    List<int> TempOff2;
    int index1 = 0;
    double Time1 = int.MaxValue, Time2 = int.MaxValue;

    while (pp < PopulationSize)
    {
        Team1 = new List<int>();
        Team2 = new List<int>();
        TempOff1 = new List<int>();
        TempOff2 = new List<int>();
        index1 = 0;
        Time1 = int.MaxValue;
        Time2 = int.MaxValue;
        int[] MinMax = new int[2];

        int maxindex = 0, minindex = 0;
        MinMax = FindMaximumMinimumTeam(SOLUTIONS[pp].Route);
        minindex = MinMax[0];
        maxindex = MinMax[1];
        //extract maximum team from 
        Team1 = ExtractTeamFromSolution(SOLUTIONS[pp].Route, maxindex);
        //remove start and end city
        Team1.RemoveAt(0);
        Team1.RemoveAt(Team1.Count - 1);

        Team2 = ExtractTeamFromSolution(SOLUTIONS[pp].Route, minindex);
        Team2.RemoveAt(0);
        Team2.RemoveAt(Team2.Count - 1);
        //add team2 to team1
        //all cities are in team1
        Team1.AddRange(Team2);
        Team2.Clear();

        //add other teams(except max and min team) to the team2
        for (int i = 1; i < NoOfTeams + 1; i++)
        {
            if (i != maxindex && i != minindex)
            {
                Team2.AddRange(ExtractTeamFromSolution(SOLUTIONS[pp].Route, i));
            }
        }

        TempOff1.Add(StartCity);
        TempOff1.Add(endCity);
        TempOff2.Add(StartCity);
        TempOff2.Add(endCity);
        //index1 = TempOff1.Count - 1;
        //index2 = TempOff2.Count - 1;

        while (index1 != Team1.Count)
        {
            Time1 = int.MaxValue;
            Time2 = int.MaxValue;

            //fill off1
            //i want to add team1[index1] to the off1 or off2 righ befor the end city
            if (CalculateTeamTime(TempOff1, Team1.ElementAt(index1), TempOff1.Count - 2) < TMAX)
            {
                Time1 = TimeTable[TempOff1.ElementAt(TempOff1.Count - 2)][Team1.ElementAt(index1)];
            }
            if (CalculateTeamTime(TempOff2, Team1.ElementAt(index1), TempOff2.Count - 2) < TMAX)
            {
                Time2 = TimeTable[TempOff2.ElementAt(TempOff2.Count - 2)][Team1.ElementAt(index1)];
            }

            //compare time1 and time2 for the winner
            if (Time1 <= Time2 
                && TempOff1.Contains(Team1.ElementAt(index1)) == false 
                && TempOff2.Contains(Team1.ElementAt(index1)) == false  
                && Team2.Contains(Team1.ElementAt(index1)) == false
                && CalculateTeamTime(TempOff1, Team1.ElementAt(index1), TempOff1.Count - 2) < TMAX)//fill off1
            {
                TempOff1.Insert(TempOff1.Count - 1, Team1.ElementAt(index1));
                index1++;
            }
            else if (Time1 >= Time2 
                && TempOff2.Contains(Team1.ElementAt(index1)) == false 
                && TempOff1.Contains(Team1.ElementAt(index1)) == false  
                && Team2.Contains(Team1.ElementAt(index1)) == false
                && CalculateTeamTime(TempOff2, Team1.ElementAt(index1), TempOff2.Count - 2) < TMAX)//fill off2
            {
                TempOff2.Insert(TempOff2.Count - 1, Team1.ElementAt(index1));
                index1++;
            }
            else// off1 and off2 do not accept the city. so i reject the city
            {
                index1++;
            }// of else

            if (CalculateTeamTime(TempOff2)>TMAX)
            {
                Console.WriteLine();
            }

        }// of while

        SOLUTIONS[pp].Route.Clear();
        SOLUTIONS[pp].Route.AddRange(TempOff1);
        SOLUTIONS[pp].Route.AddRange(TempOff2);
        SOLUTIONS[pp].Route.AddRange(Team2);

        pp++;
    }

    return SOLUTIONS;
}

【问题讨论】:

  • 你的意思是_Solutions中的具体解决方案有变化吗?这是因为它们是参考。
  • 检查此链接,可能重复stackoverflow.com/questions/222598/…
  • 我们不知道 ExtractTeamFromSolution() 做了什么,或者“将要改变”是什么意思。一个好的技术问题有预期的和实际的结果。创建一个minimal reproducible example
  • 因为参考我已经复制到解决方案。有什么办法可以防止改变_solutuions

标签: c# list pointers


【解决方案1】:

我猜solutions 是一个类,对吧?类是引用类型,即您不是对实际对象进行操作,而是对这些对象的引用进行操作。

当您调用SOLUTIONS.AddRange(_Solutions); 时,您并没有真正复制对象,而只是复制了对驻留在_Solutions 中的对象的引用并将它们存储在SOLUTIONS 中,但对象保持不变。 _Solutions 中的第一个对象与SOLUTIONS 中的第一个对象完全相同(以此类推),而不是保存相同数据的不同对象。

您必须创建对象的深层副本才能解决此问题。例如,您可以在 solutions 类中实现方法 Copy

solutions Copy()
{
    return new solutions
    {
    [... copy all fields here]
    };
}

然后更改将项目复制到的行

SOLUTIONS.AddRange(_Solutions.Select(s => s.Copy()));

您将拥有一个包含全新对象的全新列表,而不仅仅是旧列表中无聊的旧对象。

【讨论】:

    【解决方案2】:

    您实际上是在复制对_Solutions 列表中元素的引用。从_Solutions 中的元素查询信息时,元素级别的任何更改(元素内的某些属性)也将可见。

    你的代码

    List<solutions> SOLUTIONS = new List<solutions>();
    SOLUTIONS.AddRange(_Solutions);
    

    仅确保您拥有不同的引用列表(当您既想迭代 - foreach - 并在原始列表中进行更改时可能很有用,而这不能直接完成)。

    正如bradbury9 已经建议的那样,您已经深度克隆了您的列表,这实际上是为每个元素生成新的对象实例(检查here)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-13
      • 2012-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多