我应该使用struct而不是class将项放入dictionary中吗

本文关键字:中吗 dictionary class struct 我应该 | 更新日期: 2023-09-27 18:08:13

我有一个自定义的Entity类(请参阅下面的代码(。此类的对象被填充到Dictionary集合Dictionary<string, Dictionary <uint,Entity>> dt中。有人要求我使用Struct而不是Class,因为值类型不会被复制到堆中。好吧,我认为在这种情况下,类似乎是更好的选择,因为字典将只包含对Entity类型对象的引用。本例中的实体类型表示csv文件中的一行。因此,每一行都会有一个Entity类型的对象。实体类型中的封装字典包含键、表示列的值对、csv文件中一行的值。

但我想确保我没有错过任何明显的东西,所以我想最好问一下。

 public class Entity
    {
        Dictionary<string, string> dtValues = new Dictionary<string,string>(); //contains values    from CSV file.
        public Dictionary<string, string> Values
        {
          get { return dtValues; }
          set { dtValues = value; }
        }
    }

我应该使用struct而不是class将项放入dictionary中吗

有人要求我使用Struct而不是Class,因为值类型不会被复制到堆中。

那个人大错特错了。简单地说:字典本身就在堆上,所以它的内容也会在堆上。

如果你不确定应该使用引用类型还是值类型,那么你应该研究两者的优缺点(我在这里列出了一些(。但是您应该可能使用引用类型。

记住:过早优化是万恶之源。

使用结构字典总是一个非常糟糕的主意,因为当你枚举它或对它的值做任何事情时,你会一遍又一遍地复制数据,所以使用类是正确的方法,这样只会移动引用。

为了封装状态而对可变对象进行引用的类型通常应避免将这些对象暴露给外部代码。我不太明白Entity类型的用途是什么,因为唯一明显的内容是对Dictionary的引用[当然,这是一种可变类型]。

一般来说,如果希望将东西存储在集合中,并试图决定是使用类还是使用结构来存储要存储的东西,我建议如下:

  1. 如果对列表项或字典〔而不是键〕使用可变类类型,则可以编辑存储在项中的信息,而不必在过程中涉及集合本身。然而,要使项目中包含的信息可供外部代码使用,需要克隆数据项目或将数据从中复制到其他项目中。

  2. 如果对存储在集合中的内容使用不可变的类类型或任何结构类型,则编辑项中包含的信息将需要读取该项,生成更改后的版本,并将其存储回。然而,让项目中包含的信息对外部代码可用会容易得多,因为可以将其作为自己的数据类型返回。

  3. 有时有用的模式是定义一个可变结构类型,然后定义一个包装器类型,如下所示:

    public class ExposedFieldHolder<T>
    {
      public T Value;
      ExposedFieldHolder(T value) { Value = value; }
    }
    

如果Value是一个字段,而不是属性,并且创建了例如Dictionary<string, ExposedFieldHolder<someStruct>>,则可以在数据存储在字典e.g. myDict["George"]中时对其进行编辑。价值年龄++;but it will also be possible to give the data associated with an entry to outside code [e.g.返回myDict[名称]。值;`]。

在CCD_ 8中封装一个简单的暴露字段结构比简单地使用可变类更安全、更方便(因为可以返回持有者的整个CCD_,并且也比使用不可变的类或结构更方便(因为可以在不必使用读出-修改-写回序列的情况下修改列表项或字典值(。与简单地将暴露的字段结构直接存储在集合中相比,它的空间效率较低。如果在不使用`ExposedFieldHolder的情况下直接将公开的字段结构存储为字典值,则上述对George年龄的更新将需要三步过程:

var temp = myDict["George"];
temp.Age++;
myDict["George"] = temp;

但这可能仍然比不可变类或所谓的"不可变"结构所需的更好,例如

var temp = myDict["George"];
temp = new PersonDat(temp.Name, temp.Age+1, temp.FavoriteColor, temp.AstrologicalSign);
myDict["George"] = temp;

请注意,如果在使用公开的字段结构时始终遵循前一种模式,则无论结构包含哪些字段或属性或它们的出现顺序如何,代码都将是正确的。相比之下,当使用后一种模式时,必须非常小心,以确保任何值不应更改的字段或属性都能以正确的顺序传递给构造函数。有些人可能喜欢这种代码;我觉得这太可怕了。