21

使用引用类型成员定义结构(而不​​是将其定义为类)有什么意义吗?例如,要定义这个结构:

public struct SomeStruct
{
    string name;
    Int32  place;
}

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

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

4

4 回答 4

23

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

以下是一些关于何时应该选择结构而不是类的快速规则:

  1. 绝不。
    ...哦,你还在看书吗?你很执着。好的。
  2. 当您明确需要值类型语义而不是引用类型语义时。
  3. 当您有一个非常小的类型时(经验法则是内存占用小于 16 字节)。
  4. 当您的结构表示的对象将是短暂且不可变的(不会改变)时。
  5. 有时,出于与使用结构的本机代码的互操作目的。

但是,如果您做出了明智的决定并且确实确信您确实需要一个结构而不是一个类,那么您需要重新审视第 2 点并理解什么是值类型语义。Jon Skeet 的文章在这里应该对澄清区别大有帮助。

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

于 2011-04-11T12:54:23.737 回答
4

声明引用类型的字段意味着需要有空间来保存指向目标对象的引用的值。因此,在结构中拥有这样的字段是非常有意义的。

于 2011-04-11T11:57:54.977 回答
3

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

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

如果两个条件都不适用,则结构可能适合保存引用类型的字段,前提是满足以下所有条件:

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

换句话说,用于封装对象状态(而不是仅仅标识它)的对象引用应该只存储在结构字段中,如果没有执行路径可以修改它所引用的对象.

于 2012-10-31T23:09:35.517 回答
2

我很想听听更有经验的编码人员对此的优缺点有何看法,但我的理解是,作为值类型,类型的变量SomeStruct将从堆栈中分配,但会包含对包含字符串的堆上的位置。

于 2011-04-11T11:57:04.283 回答