结构 – 真实生活的例子?

在处理C#中的Structs和Classes之间的区别以及何时使用C#中的任何一个问题上,都有许多问题。 (一个句子的答案:如果你需要价值语义,则使用结构)。有很多关于如何select其中一个的指导方针,其中大部分归结为:使用一个类,除非你满足这些特定的要求,然后使用一个结构。

这一切都对我有意义。

但是,我似乎无法find任何在系统中使用结构的人的真实例子。 我是(半)C#的新手,我很难想象一个具体的情况,结构是真的是正确的select(至less,我还没有遇到过)。

所以,我转向这个世界的大脑。 有些情况下,你真的在​​一个系统中使用了一个类没有工作的结构?

那么一个class级仍然会为此工作,但我能想到的一个例子就像一个Point。 假设它是一个x和y值,你可以使用一个结构。

 struct Point { int x; int y; } 

在我看来,我宁愿有一个整数对的简单表示,而不是实际的实体没有太多(或任何)行为时定义一个具有实例的类的用法。

我用一个结构来表示一个地理位置

 struct LatLng { public decimal Lattitude { get; set; } public decimal Longitude { get; set; } } 

这代表一个实体,例如我可以将2个LatLng加在一起,或者对这个实体进行其他操作。

MSDN-结构

结构types适用于表示轻量级对象,如Point,Rectangle和Color。 虽然可以将一个点表示为一个类,但是在某些情况下,结构更有效。 例如,如果声明一个由1000个Point对象组成的数组,您将分配额外的内存来引用每个对象。 在这种情况下,这个结构比较便宜。

另外,如果你看看基本typesInt32,decimal,double ..etc,你会注意到它们都是结构体 ,它们允许它们是值types,同时允许它们实现某些关键的接口。

结构也通常用在graphics/渲染系统中。 制作点/向量结构有很多好处。

Rico Mariani 在基于价值的编程上发表了一个很好的测验 。 他讨论了在特定情况下更喜欢结构的许多理由,并在他的测验结果post中详细解释。

钱结构可能是最常见的,但电话号码或地址也是常见的。

 public struct Money { public string Currency { get; set; } public double Amount { get; set; } } public struct PhoneNumber { public int Extension { get; set; } public int RegionCode { get; set; } //... etc. } public struct FullName { public string FirstName { get; set; } public string MiddleName { get; set; } public string LastName { get; set; } } 

请记住,在.NET中,结构体的内存占用空间不应超过16字节,因为如果它们变大,CLR必须分配额外的内存。

另外,因为结构在栈上(活动)(而不是堆作为引用types),你可能会考虑使用结构,如果你需要实例化许多相同types的对象。

典型的例子是框架的nullable types ,如int? 。 这些使用结构,所以他们保留一个int值的语义,但提供了一种方法,使他们null,没有装箱,把它们转换成引用types。

当你不想通过引用传递某些东西时,你会使用一个结构体。 假设你有一个数据集合,或者一个你希望通过值传递的对象(也就是你传递给它的任何东西使用它自己唯一的副本,而不是对原始版本的引用),那么一个结构是正确的types使用。

它们为Object.GetHashCode()提供了一个默认实现,所以当对象是一个非引用types的简单集合时,您可能想要使用一个结构而不是一个类。

它们对于要精确控制数据结构的二进制布局的PInvoke / interop或低级联网场景也很有用。 (请访问www.pinvoke.net了解大量需要结构的互操作代码)

但是真的,我从来没有使用过它们。 不要冒汗不使用它们。

基本上我尝试不使用它们。 我发现他们混淆了团队中的其他开发人员,因此不值得努力。 我只find一个使用它的例子,一个自定义类枚举types,我们使用一个代码生成器从XML生成。

对我来说,关键是要定义是否要继续引用同一个对象。

当结构是另一个实体的一部分时,这使得sence本身,但实体本身。

例如,在LatLong的例子中,它使得完美的感觉。 您需要将值从一个对象复制到另一个对象,而不是继续引用相同的对象。

我经常使用结构来表示一个领域模型的值types,可能会被表示为一个枚举,但需要任意数量的任意离散值,或者我希望它有额外的行为(方法),你不能添加到一个枚举…例如,在最近的一个项目中,许多数据元素都与特定的日历月份相关联,而不是与date相关联。 所以我创build了一个CalendarMonth结构,它具有以下方法:

  • 静态CalendarMonthparsing(DateTime inValue);
  • 静态CalendarMonth分析(stringinValue);

和TryParse()方法,

  • 静态布尔TryParse(stringinValue,出CalendarMonth outVal);

和属性

  • int Month {get; 组; }
  • int年份{get; 组; }
  • DateTime StartMonthLocal {get; 组; }
  • DateTime StartMonthUTC {get; 组; }
  • DateTime EndMonthLocal {get; 组; }
  • DateTime EndMonthUTC {get; 组; }

等等

我通常不关心我的业务应用程序中的“数据密度”。 除非特别需要价值语义,否则我通常会使用一个类

这意味着我正在预见一种情况,我想比较这些事情中的两个,我希望它们显示为相同的,如果它们具有相同的值。 有了类,这实际上是更多的工作,因为我需要重写==,!=,Equals和GetHashcode,即使resharper对我来说,是额外的不必要的代码。

所以在我看来,除非你知道你想让这些东西按照价值进行比较(在这种情况下是组件的价值)

所以我认为你从来没有使用DateTime(一个结构)。

我不敢相信没有人提到XNA :在XNA中,几乎所有东西都是一个struct 。 所以,当你这样做

 Matrix rotation = Matrix.CreateRotationZ(Math.PiOver2); 

你真的创造了一个价值型。

这是因为,与应用程序编程不同,垃圾收集器运行时几毫秒的停顿是不可接受的(我们只得到16.6毫秒来渲染整个帧!) ,所以我们必须尽可能地避免分配,所以GC不必运行多less。

对于Xbox 360来说尤其如此,在这种情况下,GC的性能远不及PC上的质量 – 即使每帧平均分配一次也会导致性能下降!

我一直在使用结构实现大规模caching和延迟要求的金融机构工作。 基本上结构可以省去很多工作的垃圾收集器。

看到这些例子:

http://00sharp.wordpress.com/2013/07/03/a-case-for-the-struct/ http://00sharp.wordpress.com/2013/07/04/a-case-for-the-the- structpart-2 /

基本上,我使用Structs来build模几何和math数据,或者当我想要一个基于Value的数据结构。

我曾经使用过一个结构的唯一时间是当我build立一个Fraction结构:

 public struct Fraction { public int Numerator {get;set;} public int Denominator {get; set;} //it then had a bunch of Fraction methods like Reduce, Add, Subtract etc... } 

我觉得它代表了一个价值,就像内置的值types一样,因此,如果它的行为类似于一个值types,那么对它进行编码会更自然。

我认为.Net框架是相当现实的生活。 请参阅“结构”下的列表:

系统命名空间

在一些性能严重的情况下,结构(一个值types,从堆栈中分配)可以比一个类(一个引用types,因此从堆中分配)更好。 Joe Duffy的博客文章“ 单字读写器自旋锁 ”显示了这个的真实应用。

我之前创build的一个是StorageCapacity。 它表示0字节到N艾字节(可能已经更高到yottabyte,但是在那时exa似乎已经足够了)。 自从我在一家仓储pipe理公司工作以来,这个结构变得有意义 你可能会认为这很简单:一个具有StorageUnit(枚举)和一个数量(我使用十进制)的结构。 但是,当你添加转换,运算符和类来支持格式化,parsing等。

抽象是有用的,使您可以采取任何StorageCapacity并表示为字节,千字节等,而不必乘以或除以1024多次。

我已经给出了我在其他地方使用struct的原因( 何时在C#中使用struct ),并且我在现实生活中使用了结构:

如果我需要将大量相同的项目types存储在数组中,这可能会发生在image processing中,我会select使用结构来提高性能。

需要使用结构来在C#和C ++之间传递结构化数据。

除非我有很好的理由去使用它们,否则我会尽量避免使用它们。

我知道有些人喜欢用它们来实现价值语义,但是我发现这种行为与C#中的类的“正常”分配行为有很大的不同,以至于人们发现自己难以追踪错误,因为人们不记得那个对象是从这个对象分配的,或者有这个行为,因为它是作为一个结构而不是一个类来实现的。 (它发生在我身上不止一次,所以我给了这个警告,因为我实际上被C#结构的不合理使用所烧毁。)

我不确定这是多less用处,但我今天发现,虽然你不能在结构中有实例领域初始化器,但是你可以在课上。

因此,下面的代码会给编译错误,但是如果你把“struct”改成“class”,它就会编译。

  public struct ServiceType { public bool backEnd { get; set; } public bool frontEnd { get; set; } public string[] backEndServices = { "Service1", "Service2" }; public string[] frontEndServices = { "Service3", "Service4" }; } 

C#中的一个结构只不过是一堆粘在一起的variables而已。 如果希望每个特定types的variables代表一堆独立但相关的variables(如点的坐标)与胶带粘在一起,则通常最好使用暴露域结构而非类,而不pipe是否“一堆”是指二十个。 请注意,虽然微软的结构与类的build议对于封装单个值的数据types是适当的,但是对于其目的是封装独立但相关的值的types,它应该被认为是不适用的。 variables独立的程度越大,使用暴露域结构的优势就越大。

如果希望用一个类来封装一堆自variables,那么有两种方法可以做到这一点,这两种方法都不是非常方便。 可以使用不可变类,在这种情况下,该类types的任何非空存储位置将封装由其标识的实例持有的值,并且可以将一个存储位置复制到另一个存储位置,以使新的位置封装那些相同的值。 不幸的是,改变一个存储位置封装的值之一通常需要构造一个新的实例,就像旧的实例一样,除了该值被改变。 例如,如果有一个types为Immutable3dPoint的variables,并且想要将pt.X增加1,那么必须执行如下操作: pt = new Immutable3dPoint(pt.X+1, pt.Y, pt.Z); 如果types只封装三个值,也许可以容忍,但如果非常多的话很烦人。

另一种基于类的方法是使用可变类。 这通常需要确保类types的每个存储位置都将宇宙中唯一的引用保存到该类的一个实例中。 创build存储位置时,必须构造一个新实例并在其中存储引用。 如果希望将存储位置P的值复制到另一个存储位置Q ,则必须将所有字段或属性从一个实例复制到另一个实例(可能是通过让types实现CopyFrom方法,然后说Q.CopyFrom(P);注意,如果一个人反而说Q=P;这可能似乎有效,但是未来尝试修改P也会修改Q ,反之亦然。容易搞砸了。

暴露域结构将不可变类的便利值复制语义与可变类允许的方便分段修改相结合。 大型结构比引用不可变对象复制要慢,但是修改暴露字段结构部分的成本仅取决于修改的范围,而不取决于整体结构的大小。 相比之下,更改封装在不可变类types中的一段数据的成本将与总的类大小成比例。