使用引用类型成员定义结构是否有意义?

时间:2011-04-11 11:52:17

标签: .net struct clr value-type reference-type

使用引用类型成员定义结构是否有任何意义(而不是将其定义为类)?例如,要定义此结构:

public struct SomeStruct
{
    string name;
    Int32  place;
}

我问,因为我知道结构是一种值类型,并且在其中定义一些引用类型没有任何意义。

我是对的吗?有人可以解释一下吗?

4 个答案:

答案 0 :(得分:19)

十分之九,你应该首先创建一个类而不是一个结构。结构和类在C#中的语义非常不同,与你在C ++中可以找到的相比,例如。大多数使用结构的程序员应该使用了一个类,这样的问题就像坦率地说无关紧要。

以下是关于何时应该选择某个类的结构的快速规则:

  1. 从不。
    ...哦,你还在读书?你坚持不懈好的,没问题。
  2. 当您明确需要值类型语义时,而不是引用类型语义。
  3. 如果您的类型非常小(经验法则是内存占用量小于16个字节)。
  4. 当你的struct所代表的对象将是短暂的并且不可变(不会改变)。
  5. 偶尔使用与使用结构的本机代码进行互操作。
  6. 但是如果你做了informed decision而且确信你,事实上,需要一个结构而不是一个类,你需要重新审视第二点并理解什么值类型语义。 Jon Skeet's article here应该在很大程度上澄清这种区别。

    完成后,您应该理解为什么在值类型(struct)中定义引用类型不是问题。引用类型就像指针一样。结构内部的字段不存储实际类型;相反,它存储指向该类型的指针(或引用)。使用包含引用类型的字段声明结构没有任何矛盾或错误。它既不会“减慢对象”,也不会“调用GC”,这是你在评论中表达的两个问题。

答案 1 :(得分:3)

声明引用类型的字段意味着需要有空间来保存指向目标对象的引用的。因此,在结构中使用这些字段是完全合理的。

答案 2 :(得分:2)

我很想知道更有经验的程序员对此的优缺点所说的,但我的理解是,作为一种值类型,将从堆栈中分配一个SomeStruct类型的变量,但会包含对包含字符串的堆上位置的引用。

答案 3 :(得分:2)

通常,如果满足下列条件之一,结构应仅包含引用类型的公共和/或可变字段:

  1. 该类型的所有实例都可以视为固有不可变(如`string`的情况)
  2. 结构的语义清楚地表明字段标识它引用的对象,而不是封装它的状态,并且字段引用的对象的状态是被认为是结构的一部分。例如,在KeyValuePair< string,Form>中,人们会期望`Value`来标识表单实例;在屏幕上移动表单会改变`Value.Bounds`,但不会被认为会改变`Value`(无论屏幕上的位置如何,它都会继续引用相同的形式)

如果两种条件均不适用,则在满足以下所有条件的情况下,结构可能适合保留参考类型的字段:

  1. 该字段永远不会引用结构本身不会创建的任何可变对象。
  2. 绝不能将引用暴露给任何可能在将来改变它引用的对象的代码,也不应该暴露给它。
  3. 必须在将引用存储在字段中之前执行将要对该字段引用的对象执行的所有突变。

换句话说,用于封装对象状态的对象引用(而不仅仅是识别它)应该只存储在struct字段中,如果没有执行路径,通过该对象引用它引用的对象可能会被修改。