我习惯在VB6中使用Structures,并尝试使用.NET来避免它们。只是想知道在2010年使用结构而不是类是否被认为是讨厌的?
感谢您的帮助。
答案 0 :(得分:16)
选择Structure
需要考虑,而不是天生就是“讨厌”。结构可以令人讨厌的原因;然而,Class
也有可能以自己的方式讨厌......
基本上,当您决定使用这两种面向对象的容器时,决定如何使用内存。
VB.NET中有与Structure
和Class
相关的不同语义,它们代表不同的内存使用模式。
创建Class
即可创建引用类型。
创建Structure
即可创建值类型。
如果您是音频学习者,还可以在YouTube上获得一些好video resources。
互联网上的许多文章,就像这些MSDN文章一样,教授基础知识和细节:
实施例
答案 1 :(得分:6)
存在结构是因为在某些情况下它们比类更有意义。它们对于表示小的抽象数据类型特别有用,例如3D点,纬度 - 经度,有理数等。
使用结构的基本动机是避免GC压力。由于结构体是内联的(在堆栈上或在你放入的任何容器内)而不是在堆上,它们通常会导致更少的小分配,如果你需要保存一百万个点或有理数的数组,这会产生巨大的差异
需要注意的一个关键问题是结构是值类型,因此通常按值传递(明显的例外是ref和out参数)。这具有重要意义。例如:
Point3D[] points = ...;
points[9].Move(0, 0, 5);
上面的代码工作正常,并将第10点的z坐标增加5.但是下面的代码:
List<Point3D> points = ...;
points[9].Move(0, 0, 5);
仍将编译并运行,但您会发现第10个点的z坐标保持不变。这是因为List的索引运算符返回该点的副本,它是您正在调用Move
的副本。
解决方案非常简单。始终通过只读标记所有字段使结构不可变。如果您仍然需要Move
点,请在Point3D类型上定义+并使用赋值:
points[9] = points[9] + new Point3D(0, 0, 5);
答案 2 :(得分:3)
在不理解其含义的情况下使用任何被认为是非常糟糕的。
结构是value types, not reference types - 因此,它们的行为略有不同。传递值类型时,修改位于副本上,而不是原始副本上。将值类型分配给object
引用(例如,在非通用列表中)时,会发生boxing。请务必阅读选择其中一个的完整效果。
答案 3 :(得分:3)
阅读this以获得结构与类的一些理解益处,反之亦然。
在以下情况下,结构可能更合适:
- 您拥有少量数据,只需要相当于UDT (以前版本的Visual Basic
的(用户定义类型)- 您在每个实例上执行大量操作并会产生 堆管理导致性能下降
- 您无需继承结构或专业化 其实例之间的功能
- 您不打包并取消装箱结构
- 您正在通过托管/非托管边界传递blittable数据
在以下情况下优先选择课程:
- 您需要使用继承和多态
- 您需要在创建时初始化一个或多个成员
- 您需要提供一个未参数化的构造函数
- 您需要无限制的事件处理支持
答案 4 :(得分:2)
直接回答你的问题,在VB.NET中使用结构并没有什么不妥。与任何设计决策一样,您需要考虑此决策的后果。
重要的是你要意识到一个阶级和一个结构之间的区别,这样你才能做出有关哪个是合适的有根据的决定。正如Alex等人所述,结构和类之间的关键区别之一是结构被视为值类型而类被视为引用类型。
引用类型使用copy-by-reference sematics,这意味着当创建或复制对象时,只在堆栈上分配指向实际对象的指针,实际的对象数据将在堆上分配。
相比之下,值类型具有按值复制的代码,这意味着每次复制值类型(例如结构)时,整个对象都会被复制到堆栈上的新位置/
对于具有少量数据的对象,这不是一个真正的问题,但是如果你有大量的数据,那么使用引用类型在堆栈分配方面可能会更便宜,因为只有一个指针将是复制到堆栈。
微软have guidelines on the use of structures更准确地描述了类和结构之间的差异以及选择其中一个的结果
答案 5 :(得分:1)
从行为的角度来看,有三种类型的东西&#39;在.net:
Eric Lippert真的不喜欢上面的第2组,因为.net并不擅长处理它们,有时会把它们当作#1组或者#3组来对待。尽管如此,有时候可变值类型在语义上比其他任何东西都更有意义。
例如,假设一个人有一个矩形,一个想要制作另一个像第一个那样的矩形,但是要高一倍。恕我直言的清洁工说:
Rect2 = Rect1 ' Makes a new Rectangle that's just like Rect1 Rect2.Height = Rect2.Height*2
而不是说
Rect2 = Rect1.Clone ' Would be necessary if Rect1 were a class Rect2.Height = Rect2.Height*2
或
Rect2 = New Rectangle(Rect1.Left, Rect1.Top, Rect1.Width, Rect1.Height*2)
当使用类时,如果想要一个与现有对象略有不同的对象,则必须在变异对象之前考虑是否有其他人想要使用原始对象;如果是这样,必须复制它,然后对副本进行所需的更改。结构,没有这样的限制。
考虑值类型的一种简单方法是将每个赋值操作视为复制原始类型,但其方式比克隆类类型要便宜得多。如果一个人最终会克隆很多对象,就像人们在没有克隆的情况下分配引用一样,这是支持结构的重要论据。