【问题标题】:Dictionary.Value changes with the change of object assigned to itDictionary.Value 随着分配给它的对象的变化而变化
【发布时间】:2018-07-20 08:22:42
【问题描述】:

我正在尝试制作 (string, WI) 的字典,其中 WI 是我定义的类。

代码如下所示:

namespace Tracking
{
    class Program
    {
        static public Dictionary<string, WI> Dict = new Dictionary<string, WI>();

        static void Main(string[] args)
        {
            WI oWI = new WI(some_arg);
            string key = "mykey";
            if (!Dict.ContainsKey(key))
            {
                Dict.Add(key, oWI);
            }

            var before = Dict[key];

            oWI = new WI(another_arg);

            var after = Dict[key];
        }
    }
}

问题是oWI改了之后,Dict[key].Value里面的东西也都变了,即“before”和“after”的值不一样。

他们之间似乎有联系。如何断开连接?字典不应该制作自己的 WI 对象副本吗?我做错了什么?

【问题讨论】:

  • 这不是真的。实际上oWI 是一个变量。这就像一个城市的高速公路标志,例如显示通往伦敦的方向。现在您保留标志上的文字,但将方向更改为巴黎。发生了什么?您是否已将伦敦更改为巴黎,或者您刚刚更改了标志?您还没有更改仍然存储旧实例而不是新实例的字典。
  • 无法重新创建。如果我输入一个微不足道的WI,那么before 会得到最初添加到字典中的值,这不会通过更新oWI 来改变。请包含显示此行为的最小重新创建。
  • @Richard 我将编辑问题。我试图保持简短。
  • 如何检查两个实例是否相同?

标签: c# dictionary object


【解决方案1】:

TL;DR:使用提供的代码未显示报告的行为

WI 可能正在做一些“聪明”的事情,如果没有 WI 的定义,就无法重新创建。

演示

以下代码输出

之前:一个 之后:一

即。更改引用 oWI 不会更改对先前由 oWI 引用的对象的其他引用

using System;
using System.Collections.Generic;

class WI
{
    public string Data { get; private set; }

    public WI(string x)
    {
        Data = x;
    }
}
class Program
{
    static public Dictionary<string, WI> Dict = new Dictionary<string, WI>();
    const string some_arg = "One";
    const string another_arg = "Two";

    static void Main(string[] args)
    {
        WI oWI = new WI(some_arg);
        string key = "mykey";
        if (!Dict.ContainsKey(key))
        {
            Dict.Add(key, oWI);
        }

        var before = Dict[key];
        Console.WriteLine($"Before: {before.Data}");

        oWI = new WI(another_arg);

        var after = Dict[key];
        Console.WriteLine($"After: {after.Data}");
    }
}

【讨论】:

    【解决方案2】:

    您需要将oWI1 对象复制到另一个新对象。如果WI 类是引用类型,则需要实现ICloneable 接口并进行深度克隆。让两个对象指向不同的引用。

    例如:

    WI 实现ICloneable 的do Clone 方法,它会返回一个新的WI 对象。

    public class WI : ICloneable
    {
        public int age1 { get; set; }
        public object Clone()
        {
            return new WI() { age1 = this.age1 };
        }
    }
    

    当你使用时

    var after = Dict[key].Clone() as WI;
    

    【讨论】:

      【解决方案3】:

      问题在于字典只保留了对创建对象 oWI 的引用。因此,如果 oWI(字典指向的)发生更改,这也会反映在字典中。

      考虑直接在字典中创建对象,以访问与字典隔离的对象。像这样:

      string key = "mykey";
      if (!Dict.ContainsKey(key))
      {
          Dict.Add(key, new WI(some_arg));
      }
      

      【讨论】:

      • 更改oWI 不会更改字典(尝试原始代码:报告的行为不会发生)。你混淆了参考和参考。
      • (澄清)更改oWI 引用的对象的状态将导致更改对同一对象的其他引用可见。更改 oWI 以引用不同的对象不会被对原始对象的其他引用看到。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-15
      • 2021-12-05
      • 2014-06-25
      • 1970-01-01
      • 1970-01-01
      • 2019-08-27
      • 2020-01-21
      相关资源
      最近更新 更多