【问题标题】:How do you take a copy of a dictionary's KeyValuePair without it maintaining a reference to the original dictionary? Cloneable KVP?如何在不保留对原始字典的引用的情况下获取字典的 KeyValuePair 的副本?可克隆KVP?
【发布时间】:2021-10-28 07:35:53
【问题描述】:

所以我有一个程序,它开始使用精确数量的步骤构建从给定起点到同一点的可能路径字典。

我首先为开始和结束步骤的每个独特组合添加一个字典行,然后我有一个方法,它基本上可以找到所有可以填充其间剩余步骤的独特组合。

看起来像这样:

        private int CreatePathsWithAllSteps(int pathKey)
    {
        try
        {
            //Make sure we reiterate through the list of paths for all the configured steps to complete the paths.
            for (int i = 0; i < MaxSteps - 2; i++)
            {
                //Create a fresh list of new paths with each complete iteration so we're not duplicating added paths
                Dictionary<int, TravelPath> newPaths = new Dictionary<int, TravelPath>();

                foreach (KeyValuePair<int, TravelPath> path in Paths)
                {
                    //We need to find the list of Destination Pairs we can use with the existing path
                    Dictionary<string, DestinationPair> pairsToUse = FindDestinationPairsToUseNext(path, i+1);
                    bool isfirstiteration = true;

                    //***Issue*** 1 - Creating the copy of the KVP so I can reuse it to create all possible combinations of it with the next step in the path.
                    //I use the values of the KVP from the dictionary i'm iterating through. This seems to create them as reference paths back to the original dictionary.  
                    KeyValuePair<int, TravelPath> pathCopy = new KeyValuePair<int, TravelPath>(path.Key, path.Value);
                    
                    foreach (KeyValuePair<string, DestinationPair> TP in pairsToUse)
                    {
                        //Make sure we're using already existing paths first and then create new ones for all other options. 

                        if (isfirstiteration)
                        {
                            //First time through use path already created at this point
                            if (path.Value.Path[i].Name != TP.Value.Name)
                            {
                                //Destination Pair is different to the previous pair so add it
                                path.Value.Path[i + 1] = TP.Value;
                                isfirstiteration = false;
                            }
                            
                        }
                        else
                        {
                            //for this one, create a new copy of the path we're working on and then update with next step
                            if (pathCopy.Value.Path[i].Name != TP.Value.Name)
                            {
                                //***Issue*** 2 - When I use the value of the copied KVP to create a new KVP to add to the dictionary this also seems to create a reference back to the copy and by extension the original value from the original dictionary we're iterating through. 
                                KeyValuePair<int, TravelPath> tempTP = new KeyValuePair<int, TravelPath>(pathKey, pathCopy.Value);
                                //***Issue*** 3 - I then edit the value of the KVP created in the previous line, and this changes the value in the original main Paths dictionary.
                                tempTP.Value.Path[i + 1] = TP.Value;
                                if (!PathValueComparer(tempTP, newPaths, Paths))
                                {
                                    newPaths.Add(pathKey, pathCopy.Value);
                                    pathKey++;
                                }
                                
                            }
                            
                        }
                    }

                   
                }

                foreach(KeyValuePair<int, TravelPath> path in newPaths)
                {
                    Paths.Add(path.Key, path.Value);
                }
            }
            return pathKey;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            return pathKey;
        }

    }

我添加了一些额外的带有 ***Issue*** 前缀的 cmets,这样您就可以看到我认为问题出在哪里以及我认为这里发生了什么。

现在距离我上次进行常规编码已经 3 或 4 年了,所以我有点生疏(请不要过多地评价我的代码,哈哈),但我确实记得以前在处理字典时遇到过类似的问题,并且我似乎记得解决方案是拥有一个同时实现 IDictionary 和 ICloneable 的自定义字典,因此您可以调用 .Clone() 来创建一个未引用的副本,然后可以对字典进行临时编辑并使用这些值而不会被引用回来到您的源字典。

我想我会尝试用 KVP 做一些类似的事情,但似乎没有一个 KVP 接口可以实际用作自定义实现的基础。

我觉得我可能只是创建一个可克隆的字典,然后在从克隆版本中获取我需要的 KVP 副本之前克隆它,但是对于这项工作,我真的不需要完整的字典可克隆,只是KVP,所以看起来有点浪费

所以我想问题是,有没有更好的方法来打破 KVP 和 Dictionary 的值之间的引用?

【问题讨论】:

  • 这与 KeyValuePair 无关(这是一个 struct,因此总是按值复制)以及与您的 TravelPath class,通过引用复制。你的问题到底是什么?
  • @charlie 啊,好吧,在那种情况下,我想我的问题是我如何确保当我这样做时tempTP.Value.Path[i + 1] = TP.Value; 我确保字典值tempTP 是从中复制的,它没有被编辑,它目前是……我想我的问题的解决方案是在我的 TravelPath 类中实现 ICloneable,然后我可以克隆 KVP 的值……听起来它可以解决问题。
  • 确实,但我们对TravelPath一无所知,因此无法提供建议
  • new KeyValuePair&lt;int, TravelPath&gt;(path.Key, path.Value); -> new KeyValuePair&lt;int, TravelPath&gt;(path.Key, new TravelPath(...)); ?
  • @caiusJard 哦,工作得很好,谢谢。

标签: c# .net dictionary key-value icloneable


【解决方案1】:

本质问题是,虽然内存中有两个不同的 KeyValuePair,但它们引用的是同一个 TravelPath 类

 //this line
KeyValuePair<int, TravelPath> pathCopy = new KeyValuePair<int, TravelPath>(path.Key, path.Value);

//sets up this in memory

123 <-- path.Key, path.Value --> TravelPathX <-- pathCopy.Value, pathCopy.Key --> 123

值类型被克隆,因此有两个不同的 123,但两个 Value 属性都引用 TravelPath 的同一个实例。修改 TravelPath 实例的属性意味着 path 和 pathcopy 都可以看到

没有看到 TravelPath 很难进一步了解,但简单的解决方案是创建一个新的 TravelPath 并复制您想要的属性。请记住克隆您想要修改的任何内容,例如,如果 TravelPath 有一个列表,它也需要 newing(如果您要修改列表中的对象而不是删除和创建新对象,那么这些对象需要 @987654323 @ing 也..)

//this line
var pathCopy = new KeyValuePair<int, TravelPath>(path.Key, new TravelPath { Name = path.Value.Name ... });

//Would set up this in memory
123 <-- path.Key, path.Value --> TravelPathX
                                 TravelPathY <-- pathCopy.Value, pathCopy.Key --> 123

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-08
    相关资源
    最近更新 更多