简体   繁体   English

在C#中更改结构的大小是一个重大改变吗?

[英]Is changing the size of a struct a breaking change in C#?

Just curious, is changing the size of a struct/value type a breaking change in C#? 只是好奇,改变结构/值类型的大小是C#中的突破性变化? Structs tend to be more sensitive in terms of memory layout since altering them directly affects the size of arrays/other structs. 结构在内存布局方面往往更敏感,因为更改它们会直接影响数组/其他结构的大小。 Are there any examples of code that breaks, either binary-wise or source-wise, after the layout of a struct in a library it uses is changed? 在使用的库中的结构布局发生变化之后,是否存在任何代码断开的示例(二进制或源代码)?

NOTE: By "breaks," I mean it fails to compile at all or the IL is invalidated. 注意:通过“中断”,我的意思是它根本无法编译或IL无效。 So for example I wouldn't consider this a breaking change: 例如,我不认为这是一个重大变化:

// My.Library v1
public struct MyStruct {}

// My.Library v2
public struct MyStruct { int _field; }

// App code
using My.Library;
using System.Runtime.InteropServices;

Console.WriteLine(Marshal.SizeOf<MyStruct>()); // before printed 1, now prints 4

because it still runs. 因为它仍在运行

Changing size by adding fields is ok for strictly managed code. 通过添加字段来改变大小对于严格管理的代码是可以的

Adding field(s) is non-breaking change as code will be re-JIT-ed with the new type and all allocations will use correct size. 添加字段是不间断的更改,因为代码将使用新类型重新进行JIT编辑,并且所有分配将使用正确的大小。 Since it is value type the new fields will be properly initialized with empty values anyway. 由于它是值类型,因此无论如何都将使用空值正确初始化新字段。

Removing/changing types of existing fields(s) or properties is definitely breaking change. 删除/更改现有字段或属性的类型肯定是一种变化。

Value types are sealed - so no other libraries can derive from that type - so unlike classes they can't create problems with "this derived class did not implement a new virtual property/interface method". 值类型是密封的 - 因此没有其他库可以从该类型派生 - 所以与类不同,它们不能创建“此派生类没有实现新的虚拟属性/接口方法”的问题。

Note: if a value type is used for interop or any other kind of binary serialization outside of your control than any change is breaking. 注意:如果值类型用于interop或控制之外的任何其他类型的二进制序列化,则任何更改都会中断。

Ie someone else used MyLib.Point {int x;int y;} to save a list of points with binary serialization to a file. 即其他人使用MyLib.Point {int x;int y;}将带有二进制序列化的点列表保存到文件中。 If now "MyLib" adds a new field to MyLib.Point than the serialized data no longer can be read with binary serialization. 如果现在“MyLib”向MyLib.Point添加新字段, MyLib.Point不再能够使用二进制序列化读取序列化数据。 Similar issue with native interop. 与本机互操作类似的问题。

Yes, source code incompatibilities are definitely possible, even in strictly managed code, if you add a new field. 是的,如果添加新字段,即使在严格管理的代码中,源代码不兼容也是可能的。 Taking your example, this compiles with version 1 but not version 2: 以您的示例为例,这将编译版本1但不编译版本2:

MyStruct s;
Console.WriteLine(s);

The reason is that C# allows a struct local to be used if all the fields have been assigned values. 原因是如果为所有字段分配了值,C#允许使用struct local。 In version 1, there are no fields so s is "definitely assigned". 在版本1中,没有字段,因此s是“明确分配”。 However if a field is added in version 2, even if it is private, then this no longer compiles because s is no longer definitely assigned. 但是,如果在版本2中添加了一个字段,即使它是私有的,那么这也不再编译,因为s不再是明确分配的。

This case should be binary compatible since the CLR guarantees initialization of fields to their default values. 这种情况应该是二进制兼容的,因为CLR保证字段初始化为其默认值。

Jared Parsons had a good blog post on the subject of private fields in structs where he details other cases where changing private implementation details would be dangerous (for unsafe code) or breaking. Jared Parsons在结构中的私人领域有一篇很好的博客文章 ,其中详细说明了其他更改私有实施细节(对于不安全的代码)或破坏的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM